From 26c05f865c06f8d792c173cb982cca4eb8dc42aa Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Tue, 27 Aug 2024 11:20:22 +0200 Subject: [PATCH] #296: first draft of the cli with build command --- package-lock.json | 18 +++++++ packages/cli/CHANGELOG.md | 4 ++ packages/cli/README.md | 9 ++++ packages/cli/package.json | 45 ++++++++++++++++ packages/cli/src/CliManager.ts | 23 ++++++++ packages/cli/src/arguments/ArgumentManager.ts | 33 ++++++++++++ packages/cli/src/arguments/index.ts | 2 + packages/cli/src/commands/CommandManager.ts | 26 ++++++++++ .../commands/implementations/BuildCache.ts | 17 ++++++ packages/cli/src/commands/index.ts | 2 + .../cli/src/commands/interfaces/Command.ts | 5 ++ packages/cli/src/lib.ts | 2 + packages/cli/tsconfig.json | 21 ++++++++ packages/cli/vite.config.ts | 10 ++++ packages/jitar/package.json | 5 +- packages/jitar/rollup.config.js | 16 ++++++ packages/jitar/src/cli.ts | 6 +++ packages/plugin-vite/src/index.ts | 52 +++++++------------ .../src/definitions/RuntimeDefaults.ts | 2 +- packages/server-nodejs/src/lib.ts | 1 + .../src/utils/RuntimeConfigurator.ts | 14 ----- 21 files changed, 264 insertions(+), 49 deletions(-) create mode 100644 packages/cli/CHANGELOG.md create mode 100644 packages/cli/README.md create mode 100644 packages/cli/package.json create mode 100644 packages/cli/src/CliManager.ts create mode 100644 packages/cli/src/arguments/ArgumentManager.ts create mode 100644 packages/cli/src/arguments/index.ts create mode 100644 packages/cli/src/commands/CommandManager.ts create mode 100644 packages/cli/src/commands/implementations/BuildCache.ts create mode 100644 packages/cli/src/commands/index.ts create mode 100644 packages/cli/src/commands/interfaces/Command.ts create mode 100644 packages/cli/src/lib.ts create mode 100644 packages/cli/tsconfig.json create mode 100644 packages/cli/vite.config.ts create mode 100755 packages/jitar/src/cli.ts diff --git a/package-lock.json b/package-lock.json index d7c5077c..58ad6c9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1243,6 +1243,10 @@ "resolved": "packages/caching", "link": true }, + "node_modules/@jitar/cli": { + "resolved": "packages/cli", + "link": true + }, "node_modules/@jitar/plugin-vite": { "resolved": "packages/plugin-vite", "link": true @@ -13905,6 +13909,15 @@ "@jitar/runtime": "*" } }, + "packages/cli": { + "name": "@jitar/cli", + "version": "0.7.4", + "license": "MIT", + "dependencies": { + "@jitar/caching": "*", + "@jitar/server-nodejs": "*" + } + }, "packages/create-jitar": { "version": "0.7.4", "license": "MIT", @@ -13928,12 +13941,17 @@ "express-http-proxy": "^2.0.0", "fs-extra": "^11.2.0", "glob-promise": "6.0.5", + "jitar": "file:", "mime-types": "^2.1.35", "tslog": "^4.9.2", "yargs": "^17.7.2", "zod": "^3.22.4" }, + "bin": { + "jitar": "dist/cli.js" + }, "devDependencies": { + "@jitar/cli": "*", "@jitar/runtime": "*", "@jitar/server-nodejs": "*" }, diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md new file mode 100644 index 00000000..80f29432 --- /dev/null +++ b/packages/cli/CHANGELOG.md @@ -0,0 +1,4 @@ + +# Changelog + +This package doesn't keep a changelog. See the changelog in the [github repository](https://github.com/MaskingTechnology/jitar/blob/main/CHANGELOG.md) \ No newline at end of file diff --git a/packages/cli/README.md b/packages/cli/README.md new file mode 100644 index 00000000..5528c804 --- /dev/null +++ b/packages/cli/README.md @@ -0,0 +1,9 @@ + +# Jitar Caching + +This package contains the components for creating the runtime cache for [Jitar](https://jitar.dev) applications. + +For more information about Jitar: + +* [Visit our website](https://jitar.dev) +* [Read the documentation](https://docs.jitar.dev). diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 00000000..c1743829 --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,45 @@ +{ + "name": "@jitar/cli", + "version": "0.7.4", + "description": "JavaScript CLI library for the Jitar runtime.", + "author": "Masking Technology (https://jitar.dev)", + "license": "MIT", + "type": "module", + "types": "dist/lib.d.ts", + "exports": { + ".": "./dist/lib.js" + }, + "files": [ + "CHANGELOG.md", + "README.md", + "dist" + ], + "publishConfig": { + "access": "public" + }, + "scripts": { + "test": "vitest run", + "test-coverage": "vitest run --coverage", + "lint": "eslint . --ext .ts", + "build": "tsc -p tsconfig.json", + "clean": "rm -rf dist", + "prepublishOnly": "npm run clean && npm run build" + }, + "dependencies": { + "@jitar/caching": "*", + "@jitar/server-nodejs": "*" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/MaskingTechnology/jitar.git" + }, + "bugs": { + "url": "https://github.com/MaskingTechnology/jitar/issues" + }, + "homepage": "https://jitar.dev", + "keywords": [ + "javascript", + "cli", + "jitar" + ] +} diff --git a/packages/cli/src/CliManager.ts b/packages/cli/src/CliManager.ts new file mode 100644 index 00000000..c62c24f1 --- /dev/null +++ b/packages/cli/src/CliManager.ts @@ -0,0 +1,23 @@ + +import { ArgumentManager } from './arguments'; +import { CommandManager } from './commands'; + +export default class CliManager +{ + #argumentManager: ArgumentManager; + #commandManager: CommandManager; + + constructor() + { + this.#argumentManager = new ArgumentManager(process.argv); + this.#commandManager = new CommandManager(); + } + + manage(): Promise + { + const command = this.#argumentManager.getCommand(); + const args = this.#argumentManager.getArguments(); + + return this.#commandManager.execute(command, args); + } +} diff --git a/packages/cli/src/arguments/ArgumentManager.ts b/packages/cli/src/arguments/ArgumentManager.ts new file mode 100644 index 00000000..f2d7df3c --- /dev/null +++ b/packages/cli/src/arguments/ArgumentManager.ts @@ -0,0 +1,33 @@ + +const COMMAND_INDEX = 2; + +export default class ArgumentManager +{ + #args: string[]; + + constructor(args: string[]) + { + this.#args = args; + } + + getCommand(): string + { + return this.#args[COMMAND_INDEX]; + } + + getArguments(): Map + { + const args = this.#args.slice(COMMAND_INDEX + 1); + + const map = new Map(); + + args.forEach((arg) => + { + const [key, value] = arg.split('='); + + map.set(key.trim(), value.trim()); + }); + + return map; + } +} diff --git a/packages/cli/src/arguments/index.ts b/packages/cli/src/arguments/index.ts new file mode 100644 index 00000000..438c09d9 --- /dev/null +++ b/packages/cli/src/arguments/index.ts @@ -0,0 +1,2 @@ + +export { default as ArgumentManager } from './ArgumentManager'; diff --git a/packages/cli/src/commands/CommandManager.ts b/packages/cli/src/commands/CommandManager.ts new file mode 100644 index 00000000..a2ec8380 --- /dev/null +++ b/packages/cli/src/commands/CommandManager.ts @@ -0,0 +1,26 @@ + +import Command from './interfaces/Command'; + +import BuildCache from './implementations/BuildCache'; + +export default class CommandManager +{ + #commands: Map = new Map(); + + constructor() + { + this.#commands.set('build', new BuildCache()); + } + + execute(name: string, args: Map): Promise + { + const command = this.#commands.get(name); + + if (command === undefined) + { + throw new Error(`Command ${name} not found`); + } + + return command.execute(args); + } +} diff --git a/packages/cli/src/commands/implementations/BuildCache.ts b/packages/cli/src/commands/implementations/BuildCache.ts new file mode 100644 index 00000000..6911fc1b --- /dev/null +++ b/packages/cli/src/commands/implementations/BuildCache.ts @@ -0,0 +1,17 @@ + +import { LocalFileManager } from '@jitar/server-nodejs'; +import { CacheManager } from '@jitar/caching'; + +import Command from '../interfaces/Command'; + +export default class BuildCache implements Command +{ + async execute(args: Map): Promise + { + const projectFileManager = new LocalFileManager('./'); + const appFileManager = new LocalFileManager('./dist'); + + const cacheManager = new CacheManager(projectFileManager, appFileManager); + cacheManager.build(); + } +} diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts new file mode 100644 index 00000000..22becb1d --- /dev/null +++ b/packages/cli/src/commands/index.ts @@ -0,0 +1,2 @@ + +export { default as CommandManager } from './CommandManager'; diff --git a/packages/cli/src/commands/interfaces/Command.ts b/packages/cli/src/commands/interfaces/Command.ts new file mode 100644 index 00000000..720793e7 --- /dev/null +++ b/packages/cli/src/commands/interfaces/Command.ts @@ -0,0 +1,5 @@ + +export default interface Command +{ + execute(args: Map): Promise; +} diff --git a/packages/cli/src/lib.ts b/packages/cli/src/lib.ts new file mode 100644 index 00000000..49f15827 --- /dev/null +++ b/packages/cli/src/lib.ts @@ -0,0 +1,2 @@ + +export { default as CliManager } from './CliManager'; diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 00000000..4ca2247d --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es2022", + "module": "es2022", + "rootDir": "./src/", + "moduleResolution": "node", + "declaration": true, + "outDir": "./dist", + "removeComments": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + }, + "exclude": [ + "vite.config.ts", + "node_modules", + "dist", + "test" + ] +} \ No newline at end of file diff --git a/packages/cli/vite.config.ts b/packages/cli/vite.config.ts new file mode 100644 index 00000000..f5182e1f --- /dev/null +++ b/packages/cli/vite.config.ts @@ -0,0 +1,10 @@ +// vite.config.ts +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + coverage: { + provider: 'v8' + }, + }, +}); diff --git a/packages/jitar/package.json b/packages/jitar/package.json index 717020f1..c8d67d98 100644 --- a/packages/jitar/package.json +++ b/packages/jitar/package.json @@ -18,10 +18,11 @@ "dist", "!dist/types" ], + "bin": "./dist/cli.js", "scripts": { "lint": "eslint . --ext .ts", "validate": "tsc -p tsconfig.json --noEmit", - "build": "npm run clean && rollup -c", + "build": "npm run clean && rollup -c && chmod +x dist/cli.js", "clean": "rm -rf dist", "prepublishOnly": "npm run clean && npm run build" }, @@ -30,12 +31,14 @@ "express-http-proxy": "^2.0.0", "fs-extra": "^11.2.0", "glob-promise": "6.0.5", + "jitar": "file:", "mime-types": "^2.1.35", "tslog": "^4.9.2", "yargs": "^17.7.2", "zod": "^3.22.4" }, "devDependencies": { + "@jitar/cli": "*", "@jitar/runtime": "*", "@jitar/server-nodejs": "*" }, diff --git a/packages/jitar/rollup.config.js b/packages/jitar/rollup.config.js index ed8c5b69..d27fb070 100644 --- a/packages/jitar/rollup.config.js +++ b/packages/jitar/rollup.config.js @@ -46,6 +46,22 @@ export default [ typescript() ] }, + { + external: SERVER_EXTERNALS, + input: 'src/cli.ts', + output: { + file: 'dist/cli.js', + format: 'module', + plugins: [terser({ + module: true, + mangle: false + })] + }, + plugins: [ + typescript(), + nodeResolve() + ] + }, { input: './dist/types/lib.d.ts', output: [{ file: 'dist/lib.d.ts', format: 'module' }], diff --git a/packages/jitar/src/cli.ts b/packages/jitar/src/cli.ts new file mode 100755 index 00000000..ce3e2762 --- /dev/null +++ b/packages/jitar/src/cli.ts @@ -0,0 +1,6 @@ +#!/usr/bin/env node + +import { CliManager } from '@jitar/cli'; + +const cliManager = new CliManager(); +cliManager.manage(); diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index 41c45960..7df623cf 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -23,34 +23,6 @@ function formatPath(path: string) return path; } -function createServerConfig(jitarUrl: string) -{ - return { - build: - { - target: 'esnext' - }, - server: { - proxy: { - '/rpc': jitarUrl - } - } - }; -} - -function createBootstrapCode(middlewares: string[]): string -{ - const jitarImport = `import { startClient } from "jitar/client";`; - const middlewareImports = middlewares.map((middleware, index) => `import { default as $${index} } from "${middleware}";`).join(''); - - const importFunction = `const importFunction = (specifier) => import(specifier);`; - const middlewareArray = `const middlewares = [${middlewares.map((_, index) => `$${index}`).join(', ')}];`; - - const startClient = `startClient(document.location.origin, importFunction, [], middlewares);`; - - return `${jitarImport}\n${middlewareImports}\n${importFunction}\n${middlewareArray}\n${startClient}`; -} - export default function viteJitar(sourcePath: string, jitarPath: string, jitarUrl: string, segments: string[] = [], middlewares: string[] = []): PluginOption { sourcePath = formatPath(sourcePath); @@ -66,7 +38,10 @@ export default function viteJitar(sourcePath: string, jitarPath: string, jitarUr config() { - return createServerConfig(jitarUrl); + return { + build: { target: 'esnext' }, + server: { proxy: { '/rpc': jitarUrl }} + }; }, configResolved(resolvedConfig: ResolvedConfig) @@ -113,7 +88,7 @@ export default function viteJitar(sourcePath: string, jitarPath: string, jitarUr return null; } - const cacheId = resolution.id.replace('/src/', '/.jitar/'); + const cacheId = resolution.id.replace('/src/', '/dist/'); for (const scope of scopes) { @@ -131,9 +106,20 @@ export default function viteJitar(sourcePath: string, jitarPath: string, jitarUr load(id) { - return id === BOOTSTRAPPING_ID - ? createBootstrapCode(middlewares) - : null; + if (id !== BOOTSTRAPPING_ID) + { + return null; + } + + const jitarImport = `import { startClient } from "jitar/client";`; + const middlewareImports = middlewares.map((middleware, index) => `import { default as $${index} } from "${middleware}";`).join(''); + + const importFunction = `const importFunction = (specifier) => import(specifier);`; + const middlewareArray = `const middlewares = [${middlewares.map((_, index) => `$${index}`).join(', ')}];`; + + const startClient = `startClient(document.location.origin, importFunction, [], middlewares);`; + + return `${jitarImport}\n${middlewareImports}\n${importFunction}\n${middlewareArray}\n${startClient}`; } } as PluginOption; diff --git a/packages/server-nodejs/src/definitions/RuntimeDefaults.ts b/packages/server-nodejs/src/definitions/RuntimeDefaults.ts index 1d2c6cba..94e4388a 100644 --- a/packages/server-nodejs/src/definitions/RuntimeDefaults.ts +++ b/packages/server-nodejs/src/definitions/RuntimeDefaults.ts @@ -3,7 +3,7 @@ const RuntimeDefaults = { URL: 'http://localhost:3000', SOURCE: './dist', - CACHE: './.jitar', + CACHE: './dist', INDEX: 'index.html', SERVE_INDEX_ON_NOT_FOUND: false } as const; diff --git a/packages/server-nodejs/src/lib.ts b/packages/server-nodejs/src/lib.ts index d8b0fd5d..b3125525 100644 --- a/packages/server-nodejs/src/lib.ts +++ b/packages/server-nodejs/src/lib.ts @@ -1,4 +1,5 @@ export { default as CorsMiddleware } from './middleware/CorsMiddleware.js'; +export { default as LocalFileManager } from './utils/LocalFileManager.js'; export * from './server.js'; diff --git a/packages/server-nodejs/src/utils/RuntimeConfigurator.ts b/packages/server-nodejs/src/utils/RuntimeConfigurator.ts index 11f32eb1..2b956fb2 100644 --- a/packages/server-nodejs/src/utils/RuntimeConfigurator.ts +++ b/packages/server-nodejs/src/utils/RuntimeConfigurator.ts @@ -29,8 +29,6 @@ export default class RuntimeConfigurator const url = configuration.url ?? RuntimeDefaults.URL; const healthChecks = configuration.healthChecks ?? []; - await this.#buildCache(RuntimeDefaults.SOURCE, RuntimeDefaults.CACHE); - if (configuration.repository !== undefined) return this.#configureRepository(url, healthChecks, configuration.repository); if (configuration.gateway !== undefined) return this.#configureGateway(url, healthChecks, configuration.gateway); if (configuration.worker !== undefined) return this.#configureWorker(url, healthChecks, configuration.worker); @@ -40,18 +38,6 @@ export default class RuntimeConfigurator throw new UnknownRuntimeMode(); } - async #buildCache(sourceLocation: string, cacheLocation: string): Promise - { - const projectFileManager = new LocalFileManager('./'); - await projectFileManager.delete(cacheLocation); - await projectFileManager.copy(sourceLocation, cacheLocation); - - const appFileManager = new LocalFileManager(cacheLocation); - - const cacheManager = new CacheManager(projectFileManager, appFileManager); - await cacheManager.build(); - } - async #configureRepository(url: string, healthChecks: string[], configuration: RepositoryConfiguration): Promise { const assets = await this.#getAssetFilenames(configuration.assets);