build(api): fix esm issues

Workaround NCC ESM issues by just not using ESM with NCC.
The API is still ESM, but tsup converts it to CJS before NCC consumes it, as a temporary workaround until there is something to replace NCC. Please save us bun 🙏
This seems to work fine, and as a free bonus, there is a huge build speedup because NCC isn't trying to run tsc.

Shoutout to ESM! Because forcing everyone to choose between ESM, where you need multiple workarounds a day on every package imaginable to get it to work, and CJS, where you opt yourself out of a large and growing number of NPM packages, is a fantastic idea. Interoperability is for fools!
This commit is contained in:
ryan 2023-04-01 02:27:28 +08:00
parent fae9136e23
commit e1b73c26d8
15 changed files with 3586 additions and 2162 deletions

3
.gitignore vendored
View File

@ -43,4 +43,5 @@ dist
packages/web/.next
packages/api/data
packages/*/.turbo
packages/*/.eslintcache
packages/*/.eslintcache
packages/api/.tsup-build

View File

@ -1,4 +1,4 @@
FROM node:16-alpine AS deps
FROM node:18-alpine AS deps
ENV NEXT_TELEMETRY_DISABLED 1
RUN apk add --no-cache libc6-compat
@ -13,7 +13,7 @@ RUN --mount=type=cache,id=pnpm-store,target=/root/.local/share/pnpm/store \
FROM node:16-alpine AS builder
FROM node:18-alpine AS builder
ENV NEXT_TELEMETRY_DISABLED 1
WORKDIR /usr/src/micro
@ -30,7 +30,7 @@ RUN pnpm build
FROM node:16-alpine AS runner
FROM node:18-alpine AS runner
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production

24
packages/api/convert.mjs Normal file
View File

@ -0,0 +1,24 @@
import fs from 'fs/promises';
import { extname, join, dirname } from 'path';
import { fileURLToPath } from 'url';
// convert all .js files to .cjs to work around fun ncc issues
// this only matters in dev testing build outputs because in prod
// the package.json with type:module isn't present
const walk = async (directory) => {
const handle = await fs.opendir(directory);
for await (const dirent of handle) {
if (dirent.isDirectory()) {
await walk(join(directory, dirent.name));
} else {
if (dirent.name.endsWith('.js')) {
const withoutExt = dirent.name.slice(extname(dirent.name).length);
const updatedPath = join(directory, withoutExt + '.cjs');
await fs.rename(join(directory, dirent.name), updatedPath);
}
}
}
};
const dirName = dirname(fileURLToPath(import.meta.url));
await walk(join(dirName, 'dist'));

View File

@ -4,23 +4,21 @@
"repository": "https://github.com/sylv/micro.git",
"author": "Ryan <ryan@sylver.me>",
"license": "GPL-3.0",
"private": true,
"type": "module",
"private": true,
"engine": {
"node": ">=18"
},
"scripts": {
"watch": "tsup src/main.ts src/migrations/* --target node18 --watch --clean --format esm --sourcemap --onSuccess \"node dist/main.js --inspect --inspect-brk\"",
"build": "rm -rf ./dist && ncc build src/main.ts -o dist --minify --transpile-only --v8-cache --no-source-map-register",
"watch": "tsup --watch --onSuccess \"node .tsup-build/main.cjs --inspect --inspect-brk\"",
"build": "tsup && ncc build .tsup-build/main.cjs -o dist --minify --v8-cache --no-source-map-register",
"lint": "eslint src --fix --cache",
"test": "vitest run",
"mikro-orm": "NODE_OPTIONS=\"--loader ts-node/esm\" mikro-orm"
"test": "vitest run"
},
"dependencies": {
"@fastify/cookie": "^8.3.0",
"@fastify/helmet": "^10.1.0",
"@fastify/multipart": "^7.5.0",
"@jenyus-org/graphql-utils": "^1.5.0",
"@mercuriusjs/gateway": "^1.2.0",
"@mikro-orm/core": "^5.6.15",
"@mikro-orm/migrations": "^5.6.15",
@ -34,48 +32,49 @@
"@nestjs/passport": "^9.0.3",
"@nestjs/platform-fastify": "^9.3.12",
"@nestjs/schedule": "^2.2.0",
"@ryanke/venera": "^1.0.5",
"bcryptjs": "^2.4.3",
"bytes": "^3.1.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.0",
"content-range": "^2.0.2",
"dedent": "^0.7.0",
"escape-string-regexp": "^5.0.0",
"fastify": "^4.15.0",
"file-type": "^18.2.1",
"fluent-ffmpeg": "^2.1.2",
"graphql": "^16.6.0",
"handlebars": "^4.7.7",
"istextorbinary": "^6.0.0",
"luxon": "^3.3.0",
"mercurius": "^12.2.0",
"mime-types": "^2.1.35",
"ms": "^3.0.0-canary.1",
"nanoid": "^4.0.2",
"nodemailer": "^6.9.1",
"normalize-url": "^8.0.0",
"otplib": "^12.0.1",
"passport": "^0.6.0",
"passport-jwt": "^4.0.1",
"pretty-bytes": "^6.1.0",
"reflect-metadata": "^0.1.13",
"rxjs": "^7.8.0",
"sharp": "^0.32.0",
"stream-size": "^0.0.6"
"sharp": "^0.32.0"
},
"devDependencies": {
"@mikro-orm/cli": "^5.6.15",
"handlebars": "^4.7.7",
"content-range": "^2.0.2",
"pretty-bytes": "^6.1.0",
"@swc/core": "^1.3.44",
"@jenyus-org/graphql-utils": "^1.5.0",
"bcryptjs": "^2.4.3",
"bytes": "^3.1.2",
"ms": "^3.0.0-canary.1",
"istextorbinary": "^6.0.0",
"@ryanke/venera": "^1.0.5",
"stream-size": "^0.0.6",
"@sylo-digital/scripts": "^1.0.12",
"@types/bcryptjs": "^2.4.2",
"@types/bytes": "^3.1.1",
"@types/dedent": "^0.7.0",
"dedent": "^0.7.0",
"@types/fluent-ffmpeg": "^2.1.21",
"@types/luxon": "^3.2.0",
"nanoid": "^4.0.2",
"normalize-url": "^8.0.0",
"file-type": "^18.2.1",
"@types/mime-types": "^2.1.1",
"@types/ms": "^0.7.31",
"@types/node": "^18.15.11",
"escape-string-regexp": "^5.0.0",
"@types/nodemailer": "^6.4.7",
"@types/passport-jwt": "^3.0.8",
"@types/sharp": "^0.31.1",

View File

@ -6,7 +6,7 @@ import type { OnApplicationBootstrap } from '@nestjs/common';
import { BadRequestException, Injectable, Logger, NotFoundException, PayloadTooLargeException } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import bytes from 'bytes';
import contentRange from 'content-range';
import * as contentRange from 'content-range';
import type { FastifyReply, FastifyRequest } from 'fastify';
import ffmpeg from 'fluent-ffmpeg';
import { DateTime } from 'luxon';

View File

@ -3,8 +3,7 @@
import { FlushMode } from '@mikro-orm/core';
import type { MikroOrmModuleSyncOptions } from '@mikro-orm/nestjs';
import { Logger, NotFoundException } from '@nestjs/common';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';
import { join } from 'path';
import { config } from './config.js';
import { FileMetadata } from './modules/file/file-metadata.embeddable.js';
import { File } from './modules/file/file.entity.js';
@ -33,7 +32,7 @@ export default {
throw new NotFoundException();
},
migrations: {
path: join(dirname(fileURLToPath(import.meta.url)), 'migrations'),
path: join(__dirname, 'migrations'),
tableName: MIGRATIONS_TABLE_NAME,
},
} as MikroOrmModuleSyncOptions;

View File

@ -7,13 +7,15 @@
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true,
"lib": ["es2022"],
"module": "nodenext",
// "module": "CommonJS",
// "moduleResolution": "node",
"module": "NodeNext",
"moduleResolution": "nodenext",
"target": "es2022",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node16",
"declaration": true,
"pretty": true,
"newLine": "lf",

View File

@ -0,0 +1,9 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/main.ts', 'src/migrations/*'],
outDir: '.tsup-build',
target: 'node18',
sourcemap: true,
clean: true,
});

View File

@ -1,60 +1,59 @@
{
"name": "@ryanke/micro-web",
"version": "1.0.0",
"repository": "https://github.com/sylv/micro.git",
"author": "Ryan <ryan@sylver.me>",
"license": "GPL-3.0",
"private": true,
"engine": {
"node": ">=16"
},
"scripts": {
"watch": "NODE_ENV=development concurrently \"next dev\" \"pnpm generate --watch\"",
"build": "NODE_ENV=production next build",
"lint": "NODE_ENV=production next lint",
"generate": "graphql-codegen --config codegen.yml"
},
"dependencies": {
"@apollo/client": "^3.7.10",
"@headlessui/react": "^1.7.13",
"@ryanke/pandora": "^0.0.9",
"@tailwindcss/typography": "^0.5.9",
"autoprefixer": "^10.4.14",
"classnames": "^2.3.2",
"concurrently": "^8.0.1",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.7",
"deepmerge": "^4.3.1",
"formik": "^2.2.9",
"generate-avatar": "1.4.10",
"graphql": "^16.6.0",
"http-status-codes": "^2.2.0",
"lodash": "^4.17.21",
"nanoid": "^4.0.2",
"next": "13.2.4",
"postcss": "^8.4.21",
"prism-react-renderer": "^1.3.5",
"qrcode.react": "^3.1.0",
"react": "18.2.0",
"react-dom": "^18.1.0",
"react-feather": "^2.0.9",
"react-markdown": "^8.0.6",
"rehype-raw": "^6.1.1",
"remark-gfm": "^3.0.1",
"swr": "^2.1.1",
"tailwindcss": "^3.3.1",
"yup": "^1.0.2"
},
"devDependencies": {
"@graphql-codegen/cli": "^3.2.2",
"@graphql-codegen/typescript": "3.0.2",
"@graphql-codegen/typescript-operations": "3.0.2",
"@graphql-codegen/typescript-react-apollo": "3.3.7",
"@sylo-digital/scripts": "^1.0.12",
"@types/lodash": "^4.14.192",
"@types/node": "^18.15.11",
"@types/react": "^18.0.31",
"prettier": "^2.8.7",
"typescript": "^5.0.3"
}
}
"name": "@ryanke/micro-web",
"version": "1.0.0",
"repository": "https://github.com/sylv/micro.git",
"author": "Ryan <ryan@sylver.me>",
"license": "GPL-3.0",
"private": true,
"engine": {
"node": ">=16"
},
"scripts": {
"watch": "NODE_ENV=development concurrently \"next dev\" \"pnpm generate --watch\"",
"build": "NODE_ENV=production next build",
"lint": "NODE_ENV=production next lint",
"generate": "graphql-codegen --config codegen.yml"
},
"dependencies": {
"@apollo/client": "^3.7.10",
"@headlessui/react": "^1.7.13",
"@ryanke/pandora": "^0.0.9",
"@tailwindcss/typography": "^0.5.9",
"autoprefixer": "^10.4.14",
"classnames": "^2.3.2",
"concurrently": "^8.0.1",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.7",
"deepmerge": "^4.3.1",
"formik": "^2.2.9",
"generate-avatar": "1.4.10",
"graphql": "^16.6.0",
"http-status-codes": "^2.2.0",
"lodash": "^4.17.21",
"nanoid": "^4.0.2",
"next": "13.2.4",
"postcss": "^8.4.21",
"prism-react-renderer": "^1.3.5",
"qrcode.react": "^3.1.0",
"react": "18.2.0",
"react-dom": "^18.1.0",
"react-feather": "^2.0.9",
"react-markdown": "^8.0.6",
"remark-gfm": "^3.0.1",
"swr": "^2.1.1",
"tailwindcss": "^3.3.1",
"yup": "^1.0.2"
},
"devDependencies": {
"@graphql-codegen/cli": "^3.2.2",
"@graphql-codegen/typescript": "3.0.2",
"@graphql-codegen/typescript-operations": "3.0.2",
"@graphql-codegen/typescript-react-apollo": "3.3.7",
"@sylo-digital/scripts": "^1.0.12",
"@types/lodash": "^4.14.192",
"@types/node": "^18.15.11",
"@types/react": "^18.0.31",
"prettier": "^2.8.7",
"typescript": "^5.0.3"
}
}

View File

@ -2,7 +2,6 @@ import classNames from 'classnames';
import type { Language } from 'prism-react-renderer';
import { Fragment, memo } from 'react';
import ReactMarkdown from 'react-markdown';
import rehypeRaw from 'rehype-raw';
import remarkGfm from 'remark-gfm';
import { SyntaxHighlighter } from './syntax-highlighter/syntax-highlighter';

View File

@ -7,10 +7,10 @@ interface EncryptionResult {
}
function arrayBufferToBase64(buffer: ArrayBuffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
let binary = '';
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
@ -18,10 +18,10 @@ function arrayBufferToBase64(buffer: ArrayBuffer) {
}
function base64ToArrayBuffer(base64: string) {
var binaryString = atob(base64);
var len = binaryString.length;
var bytes = new Uint8Array(len);
for (var i = 0; i < len; i++) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}

View File

@ -4,5 +4,5 @@ export function formatBytes(bytes: number, decimals = 2) {
const dm = decimals < 0 ? 0 : decimals;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
return Number.parseFloat((bytes / k ** i).toFixed(dm)) + ' ' + sizes[i];
}

View File

@ -1,5 +1,5 @@
import classNames from 'classnames';
import { FC, ReactNode } from 'react';
import { type FC, type ReactNode } from 'react';
import { Info } from 'react-feather';
export const Warning: FC<{ children: ReactNode; className?: string }> = ({ children, className }) => {

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,14 @@
#!/bin/sh
cd packages/api && node ./dist/index.js &
# Define a cleanup function
cleanup() {
pkill -P $$
}
# Trap signals and errors
trap cleanup EXIT HUP INT QUIT PIPE TERM ERR
cd packages/api && node ./dist/index.cjs &
cd packages/web && node ./server.js &
wait -n