diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..9b49524 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +Dockerfile* +docker-compose* +.dockerignore +.git +.gitignore +README.md +LICENSE +.vscode +Makefile +helm-charts +.env +.editorconfig +.idea +coverage* \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 4e89d35..c6d2a93 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,55 +1,55 @@ /** @type {import("eslint").Linter.Config} */ const config = { - root: true, - parser: "@typescript-eslint/parser", - plugins: ["isaacscript", "import"], - extends: [ - "plugin:@typescript-eslint/recommended-type-checked", - "plugin:@typescript-eslint/stylistic-type-checked", - "plugin:prettier/recommended", - ], - parserOptions: { - ecmaVersion: "latest", - sourceType: "module", - tsconfigRootDir: __dirname, - project: [ - "./tsconfig.json", - "./cli/tsconfig.eslint.json", // separate eslint config for the CLI since we want to lint and typecheck differently due to template files - "./upgrade/tsconfig.json", - "./www/tsconfig.json", - ], - }, - overrides: [ - // Template files don't have reliable type information - { - files: ["./cli/template/**/*.{ts,tsx}"], - extends: ["plugin:@typescript-eslint/disable-type-checked"], - }, - ], - rules: { - // These off/not-configured-the-way-we-want lint rules we like & opt into - "@typescript-eslint/no-explicit-any": "error", - "@typescript-eslint/no-unused-vars": [ - "error", - { argsIgnorePattern: "^_", destructuredArrayIgnorePattern: "^_" }, - ], - "@typescript-eslint/consistent-type-imports": [ - "error", - { prefer: "type-imports", fixStyle: "inline-type-imports" }, - ], - "import/consistent-type-specifier-style": ["error", "prefer-inline"], + root: true, + parser: "@typescript-eslint/parser", + plugins: ["isaacscript", "import"], + extends: [ + "plugin:@typescript-eslint/recommended-type-checked", + "plugin:@typescript-eslint/stylistic-type-checked", + "plugin:prettier/recommended", + ], + parserOptions: { + ecmaVersion: "latest", + sourceType: "module", + tsconfigRootDir: __dirname, + project: [ + "./tsconfig.json", + "./cli/tsconfig.eslint.json", // separate eslint config for the CLI since we want to lint and typecheck differently due to template files + "./upgrade/tsconfig.json", + "./www/tsconfig.json", + ], + }, + overrides: [ + // Template files don't have reliable type information + { + files: ["./cli/template/**/*.{ts,tsx}"], + extends: ["plugin:@typescript-eslint/disable-type-checked"], + }, + ], + rules: { + // These off/not-configured-the-way-we-want lint rules we like & opt into + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/no-unused-vars": [ + "error", + { argsIgnorePattern: "^_", destructuredArrayIgnorePattern: "^_" }, + ], + "@typescript-eslint/consistent-type-imports": [ + "error", + { prefer: "type-imports", fixStyle: "inline-type-imports" }, + ], + "import/consistent-type-specifier-style": ["error", "prefer-inline"], - // For educational purposes we format our comments/jsdoc nicely - "isaacscript/complete-sentences-jsdoc": "warn", - "isaacscript/format-jsdoc-comments": "warn", + // For educational purposes we format our comments/jsdoc nicely + "isaacscript/complete-sentences-jsdoc": "warn", + "isaacscript/format-jsdoc-comments": "warn", - // These lint rules don't make sense for us but are enabled in the preset configs - "@typescript-eslint/no-confusing-void-expression": "off", - "@typescript-eslint/restrict-template-expressions": "off", + // These lint rules don't make sense for us but are enabled in the preset configs + "@typescript-eslint/no-confusing-void-expression": "off", + "@typescript-eslint/restrict-template-expressions": "off", - // This rule doesn't seem to be working properly - "@typescript-eslint/prefer-nullish-coalescing": "off", - }, + // This rule doesn't seem to be working properly + "@typescript-eslint/prefer-nullish-coalescing": "off", + }, }; -module.exports = config; \ No newline at end of file +module.exports = config; diff --git a/.gitignore b/.gitignore index d493115..1bd4c7c 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ package-lock.json /mydb.sqlite /output /db -/data \ No newline at end of file +/data +/Bruno \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..523c247 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# use the official Bun image +# see all versions at https://hub.docker.com/r/oven/bun/tags +FROM oven/bun:1-debian as base +WORKDIR /app + +# install dependencies into temp directory +# this will cache them and speed up future builds +FROM base AS install +RUN mkdir -p /temp/dev +COPY package.json bun.lockb /temp/dev/ +RUN cd /temp/dev && bun install --frozen-lockfile + +# install with --production (exclude devDependencies) +RUN mkdir -p /temp/prod +COPY package.json bun.lockb /temp/prod/ +RUN cd /temp/prod && bun install --frozen-lockfile --production + +# install pandoc +RUN apt-get update && apt-get install -y pandoc + +# copy node_modules from temp directory +# then copy all (non-ignored) project files into the image +FROM base AS prerelease +COPY --from=install /temp/dev/node_modules node_modules +COPY . . + +# [optional] tests & build +ENV NODE_ENV=production +# RUN bun test +# RUN bun run build + +# copy production dependencies and source code into final image +FROM base AS release +COPY --from=install /temp/prod/node_modules node_modules +COPY --from=prerelease /app/src/index.tsx /app/src/ +COPY --from=prerelease /app/package.json . +COPY . . + +# copy pandoc +COPY --from=install /usr/bin/pandoc /usr/bin/pandoc + +# run the app +USER bun +EXPOSE 3000/tcp +ENTRYPOINT [ "bun", "run", "./src/index.tsx" ] \ No newline at end of file diff --git a/README.Docker.md b/README.Docker.md new file mode 100644 index 0000000..fa3048f --- /dev/null +++ b/README.Docker.md @@ -0,0 +1,22 @@ +### Building and running your application + +When you're ready, start your application by running: +`docker compose up --build`. + +Your application will be available at http://localhost:3000. + +### Deploying your application to the cloud + +First, build your image, e.g.: `docker build -t myapp .`. +If your cloud uses a different CPU architecture than your development +machine (e.g., you are on a Mac M1 and your cloud provider is amd64), +you'll want to build the image for that platform, e.g.: +`docker build --platform=linux/amd64 -t myapp .`. + +Then, push it to your registry, e.g. `docker push myregistry.com/myapp`. + +Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/) +docs for more detail on building and pushing. + +### References +* [Docker's Node.js guide](https://docs.docker.com/language/nodejs/) \ No newline at end of file diff --git a/biome.json b/biome.json index 168c992..4ded3d0 100644 --- a/biome.json +++ b/biome.json @@ -1,62 +1,60 @@ { - "$schema": "https://biomejs.dev/schemas/1.7.3/schema.json", - "formatter": { - "enabled": true, - "formatWithErrors": true, - "indentStyle": "space", - "indentWidth": 2, - "lineEnding": "lf", - "lineWidth": 80, - "attributePosition": "auto" - }, - "organizeImports": { "enabled": true }, - "linter": { - "enabled": true, - "rules": { - "recommended": false, - "complexity": { - "noBannedTypes": "error", - "noUselessThisAlias": "error", - "noUselessTypeConstraint": "error", - "useArrowFunction": "off", - "useLiteralKeys": "error", - "useOptionalChain": "error" - }, - "correctness": { "noPrecisionLoss": "error", "noUnusedVariables": "off" }, - "style": { - "noInferrableTypes": "error", - "noNamespace": "error", - "useAsConstAssertion": "error", - "useBlockStatements": "off", - "useConsistentArrayType": "error", - "useForOf": "error", - "useImportType": "error", - "useShorthandFunctionType": "error" - }, - "suspicious": { - "noEmptyBlockStatements": "error", - "noEmptyInterface": "error", - "noExplicitAny": "error", - "noExtraNonNullAssertion": "error", - "noMisleadingInstantiator": "error", - "noUnsafeDeclarationMerging": "error", - "useAwait": "error", - "useNamespaceKeyword": "error" - } - } - }, - "javascript": { - "formatter": { - "jsxQuoteStyle": "double", - "quoteProperties": "asNeeded", - "trailingComma": "all", - "semicolons": "always", - "arrowParentheses": "always", - "bracketSpacing": true, - "bracketSameLine": false, - "quoteStyle": "double", - "attributePosition": "auto" - } - }, - "overrides": [{ "include": ["./cli/template/**/*.{ts,tsx}"] }] + "$schema": "https://biomejs.dev/schemas/1.7.3/schema.json", + "formatter": { + "enabled": true, + "formatWithErrors": true, + "indentStyle": "space", + "indentWidth": 2, + "lineEnding": "lf", + "lineWidth": 80, + "attributePosition": "auto" + }, + "organizeImports": { "enabled": true }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "complexity": { + "noBannedTypes": "error", + "noUselessThisAlias": "error", + "noUselessTypeConstraint": "error", + "useArrowFunction": "off", + "useLiteralKeys": "error", + "useOptionalChain": "error" + }, + "correctness": { "noPrecisionLoss": "error", "noUnusedVariables": "off" }, + "style": { + "noInferrableTypes": "error", + "noNamespace": "error", + "useAsConstAssertion": "error", + "useBlockStatements": "off", + "useConsistentArrayType": "error", + "useForOf": "error", + "useImportType": "error", + "useShorthandFunctionType": "error" + }, + "suspicious": { + "noEmptyBlockStatements": "error", + "noEmptyInterface": "error", + "noExplicitAny": "error", + "noExtraNonNullAssertion": "error", + "noMisleadingInstantiator": "error", + "noUnsafeDeclarationMerging": "error", + "useAwait": "error", + "useNamespaceKeyword": "error" + } + } + }, + "javascript": { + "formatter": { + "jsxQuoteStyle": "double", + "quoteProperties": "asNeeded", + "semicolons": "always", + "arrowParentheses": "always", + "bracketSpacing": true, + "bracketSameLine": false, + "quoteStyle": "double", + "attributePosition": "auto" + } + } } diff --git a/bun.lockb b/bun.lockb index ec4e087..0d538dc 100644 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..4fd02bb --- /dev/null +++ b/compose.yaml @@ -0,0 +1,10 @@ +services: + convertx: + build: + context: . + volumes: + - ./data:/app/data + environment: + NODE_ENV: production + ports: + - 3000:3000 diff --git a/package.json b/package.json index 25c0a4c..23e50f0 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,6 @@ "@types/ws": "^8.5.10", "@typescript-eslint/eslint-plugin": "^7.9.0", "@typescript-eslint/parser": "^7.9.0", - "bun-types": "^1.1.8", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.1.3", "prettier": "^3.2.5", diff --git a/prettier.config.cjs b/prettier.config.cjs index 86b8f0d..c3ab6a8 100644 --- a/prettier.config.cjs +++ b/prettier.config.cjs @@ -6,7 +6,6 @@ const config = { printWidth: 80, singleQuote: false, semi: true, - trailingComma: "all", tabWidth: 2, plugins: ["@ianvs/prettier-plugin-sort-imports"], }; diff --git a/src/components/base.tsx b/src/components/base.tsx index ee0d090..ec086d8 100644 --- a/src/components/base.tsx +++ b/src/components/base.tsx @@ -6,7 +6,7 @@ export const BaseHtml = ({ children, title = "ConvertX" }) => (