From 5bd69ea16285245cab9c21c90c708991dcc98085 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Mon, 1 Jun 2026 14:48:49 +0200 Subject: [PATCH 01/11] #787: fixed middleware paths --- packages/plugin-vite/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index da7d6f03..35e150e9 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -21,7 +21,7 @@ function assureExtension(filename: string) function createJitarBundle(middlewares: string[], targetPath: string) { - const middlewareFiles = middlewares.map(name => assureExtension(`${targetPath}/${name}`)); + const middlewareFiles = middlewares.map(name => assureExtension(path.join(targetPath, name))); const jitarImport = `import { ClientBuilder, HttpRemoteBuilder } from "${JITAR_CLIENT_ID}";`; const middlewareImports = middlewareFiles.map((filename, index) => `import { default as $M${index} } from "${filename}";`).join(''); @@ -106,7 +106,7 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption { paths.vite.input = normalizePath(path.join(resolvedConfig.root)); paths.vite.output = normalizePath(path.join(paths.vite.input, resolvedConfig.build.outDir)); - paths.vite.assetOutput = normalizePath(path.join(paths.vite.input, resolvedConfig.build.assetsDir)); + paths.vite.assetOutput = normalizePath(path.join(paths.vite.output, resolvedConfig.build.assetsDir)); paths.project.root = normalizePath(path.join(paths.vite.input, pluginConfig.projectRoot)); paths.project.source = normalizePath(path.join(paths.vite.input, pluginConfig.sourceRoot)); From dc33651ea23d1805a580e4f79bb7bba03028938e Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Tue, 2 Jun 2026 10:10:22 +0200 Subject: [PATCH 02/11] #787: refactored for compatibility --- packages/plugin-vite/src/index.ts | 114 ++++-------------------------- 1 file changed, 14 insertions(+), 100 deletions(-) diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index 35e150e9..e501067c 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -1,5 +1,4 @@ -import fs from 'node:fs'; import path from 'node:path'; import { ConfigurationManager, BuildHelper } from 'jitar'; @@ -8,6 +7,7 @@ import { normalizePath, PluginOption, ResolvedConfig } from 'vite'; const JITAR_SOURCE_ID = 'jitar'; const JITAR_CLIENT_ID = 'jitar/client'; const JITAR_BUNDLE_ID = 'jitar-bundle'; +const JITAR_BUNDLE_RESOLVE_ID = `\0${JITAR_BUNDLE_ID}`; function assureExtension(filename: string) { @@ -86,9 +86,7 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption }; let buildHelper: BuildHelper; - - let jitarBundleFilename: string | undefined; - let jitarBundleImported = false; + let jitarImported = false; return { @@ -129,61 +127,22 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption await buildHelper.readApplication(); }, - options(options) + resolveId(source) { - // Add the jitar client bundle to the input - - if (options.input === undefined) - { - options.input = JITAR_BUNDLE_ID; - } - else if (typeof options.input === 'string') - { - options.input = [options.input, JITAR_BUNDLE_ID]; - } - else if (Array.isArray(options.input)) + if (source === JITAR_BUNDLE_ID) { - options.input.push(JITAR_BUNDLE_ID); + return JITAR_BUNDLE_RESOLVE_ID; } - else if (typeof options.input === 'object') - { - options.input.additionalEntry = JITAR_BUNDLE_ID; - } - - return options; - }, - resolveId: - { - order: 'pre', - async handler(source: string, importer: string | undefined) + if (source === JITAR_SOURCE_ID) { - if (source === JITAR_BUNDLE_ID) - { - return source; - } - - if (source === JITAR_SOURCE_ID) - { - // Redirect all jitar imports to the jitar client bundle - // so we can bundle the client code with the application - - if (importer?.endsWith('.segment.js') === false) - { - // Flag that the jitar bundle was imported by the application - // so we can avoid adding it to the HTML - - jitarBundleImported = true; - } - - return JITAR_BUNDLE_ID; - } + return JITAR_BUNDLE_RESOLVE_ID; } }, load(id) { - if (id === JITAR_BUNDLE_ID) + if (id === JITAR_BUNDLE_RESOLVE_ID) { return createJitarBundle(middlewares, paths.vite.output!); } @@ -219,63 +178,18 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption return null; }, - generateBundle(options, bundle) - { - // Find the jitar client bundle so we can add it later to the HTML - - const bundles = Object.entries(bundle); - - for (const [fileName, chunk] of bundles) - { - if (chunk.type === 'chunk' && chunk.name === JITAR_BUNDLE_ID) - { - jitarBundleFilename = fileName; - - break; - } - } - }, - - transformIndexHtml(html) + transform(code, id) { - // Add the jitar client bundle to the HTML if it wasn't imported - // by any of the application files. + // Import the Jitar bundle in the first application component - if (jitarBundleImported === true) - { - return html; - } - - if (jitarBundleFilename === undefined) + if (id.startsWith(paths.project.source!) && id.endsWith('.tsx') && jitarImported === false) { - // Dev mode: insert the pre generated jitar bundle + jitarImported = true; - if (paths.vite.assetOutput === undefined) - { - console.warn('Output path not found!'); - - return html; - } - - const filenames = fs.readdirSync(paths.vite.assetOutput); - - const jitarFilename = filenames.find(fileName => fileName.startsWith(JITAR_BUNDLE_ID) && fileName.endsWith('.js')); - - if (jitarFilename === undefined) - { - console.warn('Jitar bundle not found! Did you build the application first?'); - - return html; - } - - const jitarBundle = fs.readFileSync(path.join(paths.vite.assetOutput, jitarFilename), 'utf-8'); - - return html.replace('${jitarBundle}\n \n Date: Tue, 2 Jun 2026 11:01:39 +0200 Subject: [PATCH 03/11] #787: added support for plain TS components --- packages/plugin-vite/src/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index e501067c..8e0d56a9 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -180,9 +180,13 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption transform(code, id) { - // Import the Jitar bundle in the first application component + // Import the Jitar bundle from the first application component + + const isFirstAppComponent = jitarImported === false + && id.startsWith(paths.project.source!) + && (id.endsWith('.ts') || id.endsWith('.tsx')); - if (id.startsWith(paths.project.source!) && id.endsWith('.tsx') && jitarImported === false) + if (isFirstAppComponent) { jitarImported = true; From 4310077f7eaa95bf32a993baa3fd8aff8fa592da Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Tue, 2 Jun 2026 14:27:57 +0200 Subject: [PATCH 04/11] #787: boyscout - fixed code generation issue keywords like 'of', 'in' etc. didn't get prefixed and postfixed with spaces resulting into broken apps. --- packages/analysis/src/static/Coder.ts | 36 ++++++++++++++----- packages/analysis/test/static/Parser.spec.ts | 30 ++++++++-------- .../analysis/test/static/fixtures/index.ts | 2 +- .../test/static/fixtures/modules.fixture.ts | 2 +- ...ations.fixture.ts => variables.fixture.ts} | 2 +- 5 files changed, 46 insertions(+), 26 deletions(-) rename packages/analysis/test/static/fixtures/{declarations.fixture.ts => variables.fixture.ts} (95%) diff --git a/packages/analysis/src/static/Coder.ts b/packages/analysis/src/static/Coder.ts index 80b41b57..3b4fea57 100644 --- a/packages/analysis/src/static/Coder.ts +++ b/packages/analysis/src/static/Coder.ts @@ -1,7 +1,7 @@ import Token from './models/Token'; import { TokenType } from './definitions/TokenType'; -import { isDeclaration, Keyword } from './definitions/Keyword'; +import { Keyword } from './definitions/Keyword'; export default class Coder { @@ -31,9 +31,10 @@ export default class Coder for (const current of this.#tokens) { - const glue = this.#needsSpacing(previous, current) ? ' ' : ''; + const prefix = this.#needsSpacingBefore(current, previous) ? ' ' : ''; + const postfix = this.#needsSpacingAfter(current) ? ' ' : ''; - code += `${glue}${current.value}`; + code += `${prefix}${current.value}${postfix}`; previous = current; } @@ -41,13 +42,13 @@ export default class Coder return code; } - #needsSpacing(previous: Token, current: Token): boolean + #needsSpacingBefore(current: Token, previous: Token): boolean { - if (previous.isType(TokenType.KEYWORD) && this.#isSpacedKeyword(previous)) + if (current.isType(TokenType.KEYWORD) && this.#isInfixKeyword(current)) { return true; } - if (previous.isType(TokenType.OPERATOR) && current.isType(TokenType.OPERATOR)) + else if (previous.isType(TokenType.OPERATOR) && current.isType(TokenType.OPERATOR)) { return true; } @@ -55,9 +56,20 @@ export default class Coder return false; } - #isSpacedKeyword(token: Token): boolean + #needsSpacingAfter(current: Token): boolean { - return isDeclaration(token.value) + return current.isType(TokenType.KEYWORD) && this.#isPrefixKeyword(current); + } + + #isPrefixKeyword(token: Token): boolean + { + return this.#isInfixKeyword(token) + || token.hasValue(Keyword.VAR) + || token.hasValue(Keyword.LET) + || token.hasValue(Keyword.CONST) + || token.hasValue(Keyword.FUNCTION) + || token.hasValue(Keyword.CLASS) + || token.hasValue(Keyword.USING) || token.hasValue(Keyword.RETURN) || token.hasValue(Keyword.ASYNC) || token.hasValue(Keyword.AWAIT) @@ -65,4 +77,12 @@ export default class Coder || token.hasValue(Keyword.NEW) || token.hasValue(Keyword.THROW); } + + #isInfixKeyword(token: Token): boolean + { + return token.hasValue(Keyword.OF) + || token.hasValue(Keyword.IN) + || token.hasValue(Keyword.AS) + || token.hasValue(Keyword.FROM); + } } diff --git a/packages/analysis/test/static/Parser.spec.ts b/packages/analysis/test/static/Parser.spec.ts index f443af14..03baff57 100644 --- a/packages/analysis/test/static/Parser.spec.ts +++ b/packages/analysis/test/static/Parser.spec.ts @@ -12,7 +12,7 @@ import { import { Parser } from '../../src/static'; -import { VALUES, IMPORTS, EXPORTS, DECLARATIONS, FUNCTIONS, CLASSES, MODULES, MODULES_STRINGS } from './fixtures'; +import { VALUES, IMPORTS, EXPORTS, VARIABLES, FUNCTIONS, CLASSES, MODULES, MODULES_STRINGS } from './fixtures'; const parser = new Parser(); @@ -402,7 +402,7 @@ describe('Parser', () => { it('should parse an empty declaration', () => { - const variable = parser.parseVariable(DECLARATIONS.EMPTY); + const variable = parser.parseVariable(VARIABLES.EMPTY); expect(variable.identifier).toEqual('name'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('let'); @@ -411,7 +411,7 @@ describe('Parser', () => it('should parse a const variable', () => { - const variable = parser.parseVariable(DECLARATIONS.CONST); + const variable = parser.parseVariable(VARIABLES.CONST); expect(variable.identifier).toEqual('name'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -421,7 +421,7 @@ describe('Parser', () => it('should parse a let declaration with value', () => { - const variable = parser.parseVariable(DECLARATIONS.LET); + const variable = parser.parseVariable(VARIABLES.LET); expect(variable.identifier).toEqual('name'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('let'); @@ -431,7 +431,7 @@ describe('Parser', () => it('should parse a var declaration with value', () => { - const variable = parser.parseVariable(DECLARATIONS.VAR); + const variable = parser.parseVariable(VARIABLES.VAR); expect(variable.identifier).toEqual('name'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('var'); @@ -441,7 +441,7 @@ describe('Parser', () => it('should parse a declaration with multiple declarations', () => { - const variable = parser.parseVariable(DECLARATIONS.MULTIPLE); + const variable = parser.parseVariable(VARIABLES.MULTIPLE); expect(variable.identifier).toEqual('name1'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('let'); @@ -451,7 +451,7 @@ describe('Parser', () => it('should parse a declaration with an expression', () => { - const variable = parser.parseVariable(DECLARATIONS.EXPRESSION); + const variable = parser.parseVariable(VARIABLES.EXPRESSION); expect(variable.identifier).toEqual('number'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -461,7 +461,7 @@ describe('Parser', () => it('should parse a declaration with an array value', () => { - const variable = parser.parseVariable(DECLARATIONS.ARRAY); + const variable = parser.parseVariable(VARIABLES.ARRAY); expect(variable.identifier).toEqual('array'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -471,7 +471,7 @@ describe('Parser', () => it('should parse a declaration with an object value', () => { - const variable = parser.parseVariable(DECLARATIONS.OBJECT); + const variable = parser.parseVariable(VARIABLES.OBJECT); expect(variable.identifier).toEqual('object'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -481,7 +481,7 @@ describe('Parser', () => it('should parse a declaration with a regex value', () => { - const variable = parser.parseVariable(DECLARATIONS.REGEX); + const variable = parser.parseVariable(VARIABLES.REGEX); expect(variable.identifier).toEqual('regex'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -491,7 +491,7 @@ describe('Parser', () => it('should parse a declaration that is destructuring an array', () => { - const variable = parser.parseVariable(DECLARATIONS.DESTRUCTURING_ARRAY); + const variable = parser.parseVariable(VARIABLES.DESTRUCTURING_ARRAY); expect(variable.identifier).toEqual('[value1,value2=true]'); expect(variable.binding).toBeInstanceOf(ESArrayBinding); expect(variable.type).toEqual('const'); @@ -517,7 +517,7 @@ describe('Parser', () => it('should parse a declaration that is destructuring an object', () => { - const variable = parser.parseVariable(DECLARATIONS.DESTRUCTURING_OBJECT); + const variable = parser.parseVariable(VARIABLES.DESTRUCTURING_OBJECT); expect(variable.identifier).toEqual('{key1,key2=false}'); expect(variable.binding).toBeInstanceOf(ESObjectBinding); expect(variable.type).toEqual('const'); @@ -542,7 +542,7 @@ describe('Parser', () => it('should parse a declaration with a non reserved keyword as name', () => { - const variable = parser.parseVariable(DECLARATIONS.KEYWORD_AS_NAME); + const variable = parser.parseVariable(VARIABLES.KEYWORD_AS_NAME); expect(variable.identifier).toEqual('as'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); @@ -552,12 +552,12 @@ describe('Parser', () => it('should parse a declaration that refers to a non reserved keyword as value', () => { - const variable = parser.parseVariable(DECLARATIONS.KEYWORD_AS_VALUE); + const variable = parser.parseVariable(VARIABLES.KEYWORD_AS_VALUE); expect(variable.identifier).toEqual('alias'); expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); expect(variable.initializer).toBeInstanceOf(ESExpression); - expect(variable.initializer?.toString(false)).toEqual('as'); + expect(variable.initializer?.toString(false)).toEqual(' as '); }); }); diff --git a/packages/analysis/test/static/fixtures/index.ts b/packages/analysis/test/static/fixtures/index.ts index c87031d7..30447888 100644 --- a/packages/analysis/test/static/fixtures/index.ts +++ b/packages/analysis/test/static/fixtures/index.ts @@ -1,7 +1,7 @@ export * from './classes.fixture'; export * from './code.fixture'; -export * from './declarations.fixture'; +export * from './variables.fixture'; export * from './exports.fixture'; export * from './functions.fixture'; export * from './imports.fixture'; diff --git a/packages/analysis/test/static/fixtures/modules.fixture.ts b/packages/analysis/test/static/fixtures/modules.fixture.ts index 43c0e7ce..55d95543 100644 --- a/packages/analysis/test/static/fixtures/modules.fixture.ts +++ b/packages/analysis/test/static/fixtures/modules.fixture.ts @@ -82,7 +82,7 @@ export {Person}; class Person{#name;#age;constructor(name,age) {this.#name=name;this.#age=age;}} const peter=new Person(name,42); async function async(){} -const a=async; +const a=async ; const b=async ()=>{}; const as=12; export {as as hi}; diff --git a/packages/analysis/test/static/fixtures/declarations.fixture.ts b/packages/analysis/test/static/fixtures/variables.fixture.ts similarity index 95% rename from packages/analysis/test/static/fixtures/declarations.fixture.ts rename to packages/analysis/test/static/fixtures/variables.fixture.ts index d8833d65..e0837c4f 100644 --- a/packages/analysis/test/static/fixtures/declarations.fixture.ts +++ b/packages/analysis/test/static/fixtures/variables.fixture.ts @@ -1,5 +1,5 @@ -export const DECLARATIONS = +export const VARIABLES = { EMPTY: "let name;", CONST: "const name = 'const';", From d8e6c383ee9dc9d2748d387f9672027d609f9cd1 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Tue, 2 Jun 2026 14:30:12 +0200 Subject: [PATCH 05/11] #787: boyscout - init template improvements --- packages/init/templates/backend/.gitignore | 2 +- packages/init/templates/react/.gitignore | 2 +- packages/init/templates/react/package.json | 2 +- packages/init/templates/vue/.gitignore | 2 +- packages/init/templates/vue/package.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/init/templates/backend/.gitignore b/packages/init/templates/backend/.gitignore index 9dc6c7d3..09da1a97 100644 --- a/packages/init/templates/backend/.gitignore +++ b/packages/init/templates/backend/.gitignore @@ -8,7 +8,7 @@ pnpm-debug.log* lerna-debug.log* node_modules -.jitar +build dist dist-ssr *.local diff --git a/packages/init/templates/react/.gitignore b/packages/init/templates/react/.gitignore index a13e852c..f19ce19a 100644 --- a/packages/init/templates/react/.gitignore +++ b/packages/init/templates/react/.gitignore @@ -8,7 +8,7 @@ pnpm-debug.log* lerna-debug.log* node_modules -.jitar +build dist dist-ssr *.local diff --git a/packages/init/templates/react/package.json b/packages/init/templates/react/package.json index 4a903441..cd2b2616 100644 --- a/packages/init/templates/react/package.json +++ b/packages/init/templates/react/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --config src/app/vite.config.ts", "build": "npm run build-domain && npm run build-app", "build-domain": "rimraf build dist && tsc -p src/tsconfig.json && jitar build", "build-app": "vite build --config src/app/vite.config.ts", diff --git a/packages/init/templates/vue/.gitignore b/packages/init/templates/vue/.gitignore index 89b15d15..09da1a97 100644 --- a/packages/init/templates/vue/.gitignore +++ b/packages/init/templates/vue/.gitignore @@ -8,8 +8,8 @@ pnpm-debug.log* lerna-debug.log* node_modules +build dist -.jitar dist-ssr *.local diff --git a/packages/init/templates/vue/package.json b/packages/init/templates/vue/package.json index f9e21b70..f9ef3ef0 100644 --- a/packages/init/templates/vue/package.json +++ b/packages/init/templates/vue/package.json @@ -4,7 +4,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "vite", + "dev": "vite --config src/app/vite.config.ts", "build": "npm run build-domain && npm run build-app", "build-domain": "rimraf build dist && tsc -p src/tsconfig.json && jitar build", "build-app": "vite build --config=src/app/vite.config.ts && vue-tsc --noEmit", From 34c0fb565ea26f899d1556333e49ee6a5ebe289d Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Wed, 3 Jun 2026 09:33:39 +0200 Subject: [PATCH 06/11] #787: boyscout - updated examples --- examples/.gitignore | 2 +- examples/access-protection/jitar.json | 2 +- examples/access-protection/package.json | 4 ++-- examples/data-transportation/jitar.json | 2 +- examples/data-transportation/package.json | 4 ++-- examples/error-handling/jitar.json | 2 +- examples/error-handling/package.json | 4 ++-- examples/health-checks/jitar.json | 2 +- examples/health-checks/package.json | 4 ++-- examples/hello-world/jitar.json | 2 +- examples/hello-world/package.json | 4 ++-- examples/load-balancing/jitar.json | 2 +- examples/load-balancing/package.json | 4 ++-- examples/middleware/jitar.json | 2 +- examples/middleware/package.json | 4 ++-- examples/multi-version/jitar.json | 2 +- examples/multi-version/package.json | 4 ++-- examples/resources/jitar.json | 2 +- examples/resources/package.json | 4 ++-- examples/segmentation/jitar.json | 2 +- examples/segmentation/package.json | 4 ++-- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/examples/.gitignore b/examples/.gitignore index 86ef7726..4e46d83c 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1,4 +1,4 @@ -.jitar +build dist node_modules package-lock.json \ No newline at end of file diff --git a/examples/access-protection/jitar.json b/examples/access-protection/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/access-protection/jitar.json +++ b/examples/access-protection/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/access-protection/package.json b/examples/access-protection/package.json index 078a372b..f015b062 100644 --- a/examples/access-protection/package.json +++ b/examples/access-protection/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json", "gateway": "jitar start --service=services/gateway.json", "worker-public": "jitar start --service=services/public.json", @@ -16,6 +16,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/data-transportation/jitar.json b/examples/data-transportation/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/data-transportation/jitar.json +++ b/examples/data-transportation/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/data-transportation/package.json b/examples/data-transportation/package.json index a53c8e95..c23028fb 100644 --- a/examples/data-transportation/package.json +++ b/examples/data-transportation/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json", "gateway": "jitar start --service=services/gateway.json", "worker-account": "jitar start --service=services/account.json", @@ -16,6 +16,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/error-handling/jitar.json b/examples/error-handling/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/error-handling/jitar.json +++ b/examples/error-handling/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/error-handling/package.json b/examples/error-handling/package.json index 9fbe4b2c..3cf6bdb3 100644 --- a/examples/error-handling/package.json +++ b/examples/error-handling/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json", "gateway": "jitar start --service=services/gateway.json", "worker-data": "jitar start --service=services/data.json", @@ -16,6 +16,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/health-checks/jitar.json b/examples/health-checks/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/health-checks/jitar.json +++ b/examples/health-checks/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/health-checks/package.json b/examples/health-checks/package.json index 67c90149..8b0572a0 100644 --- a/examples/health-checks/package.json +++ b/examples/health-checks/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json" }, "devDependencies": { @@ -13,6 +13,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/hello-world/jitar.json b/examples/hello-world/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/hello-world/jitar.json +++ b/examples/hello-world/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/hello-world/package.json b/examples/hello-world/package.json index 8b93fb5b..a6c212a9 100644 --- a/examples/hello-world/package.json +++ b/examples/hello-world/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json" }, "devDependencies": { @@ -13,6 +13,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/load-balancing/jitar.json b/examples/load-balancing/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/load-balancing/jitar.json +++ b/examples/load-balancing/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/load-balancing/package.json b/examples/load-balancing/package.json index d62cc00b..00291abd 100644 --- a/examples/load-balancing/package.json +++ b/examples/load-balancing/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json", "gateway": "jitar start --service=services/gateway.json", "worker1": "jitar start --service=services/worker1.json", @@ -16,6 +16,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/middleware/jitar.json b/examples/middleware/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/middleware/jitar.json +++ b/examples/middleware/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 3b51ebae..46b503cb 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json" }, "devDependencies": { @@ -13,6 +13,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/multi-version/jitar.json b/examples/multi-version/jitar.json index 4bb49481..0686e62b 100644 --- a/examples/multi-version/jitar.json +++ b/examples/multi-version/jitar.json @@ -1,4 +1,4 @@ { "source": "./dist", - "target": "./.jitar" + "target": "./build" } \ No newline at end of file diff --git a/examples/multi-version/package.json b/examples/multi-version/package.json index d4fb686e..a8bfaf50 100644 --- a/examples/multi-version/package.json +++ b/examples/multi-version/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json" }, "devDependencies": { @@ -13,6 +13,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/resources/jitar.json b/examples/resources/jitar.json index 3f0be613..403a2140 100644 --- a/examples/resources/jitar.json +++ b/examples/resources/jitar.json @@ -1,6 +1,6 @@ { "source": "./dist", - "target": "./.jitar", + "target": "./build", "segments": "./segments", "resources": "./resources" } \ No newline at end of file diff --git a/examples/resources/package.json b/examples/resources/package.json index 977dd630..8c65f26d 100644 --- a/examples/resources/package.json +++ b/examples/resources/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json" }, "devDependencies": { @@ -13,6 +13,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } \ No newline at end of file diff --git a/examples/segmentation/jitar.json b/examples/segmentation/jitar.json index beae5c58..1bb66f26 100644 --- a/examples/segmentation/jitar.json +++ b/examples/segmentation/jitar.json @@ -1,5 +1,5 @@ { "source": "./dist", - "target": "./.jitar", + "target": "./build", "segments": "./segments" } \ No newline at end of file diff --git a/examples/segmentation/package.json b/examples/segmentation/package.json index 98999543..22d82d43 100644 --- a/examples/segmentation/package.json +++ b/examples/segmentation/package.json @@ -5,7 +5,7 @@ "license": "MIT", "private": true, "scripts": { - "build": "rimraf dist .jitar && tsc && jitar build", + "build": "rimraf dist build && tsc && jitar build", "standalone": "jitar start --service=services/standalone.json", "gateway": "jitar start --service=services/gateway.json", "worker-data": "jitar start --service=services/data.json", @@ -16,6 +16,6 @@ "typescript": "5.9.3" }, "dependencies": { - "jitar": "0.10.5" + "jitar": "0.11.0" } } From 4071edb776ae5709bb86f4186fef00bd6c2470c9 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Wed, 3 Jun 2026 10:28:00 +0200 Subject: [PATCH 07/11] #787: Added .npmrc file --- .npmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..84503b80 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +min-release-age=4 \ No newline at end of file From 34618c6ff3fe924a062bbd05c02ccebd5f940372 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Wed, 3 Jun 2026 14:16:37 +0200 Subject: [PATCH 08/11] #787: improved code generation strategy --- packages/analysis/src/static/Coder.ts | 55 +++++++------------ .../src/static/definitions/TokenType.ts | 3 +- packages/analysis/test/static/Parser.spec.ts | 8 +-- .../test/static/fixtures/modules.fixture.ts | 2 +- 4 files changed, 27 insertions(+), 41 deletions(-) diff --git a/packages/analysis/src/static/Coder.ts b/packages/analysis/src/static/Coder.ts index 3b4fea57..2c81036d 100644 --- a/packages/analysis/src/static/Coder.ts +++ b/packages/analysis/src/static/Coder.ts @@ -1,7 +1,8 @@ import Token from './models/Token'; import { TokenType } from './definitions/TokenType'; -import { Keyword } from './definitions/Keyword'; + +const NO_TOKEN = new Token(TokenType.NONE, '', -1, 0); export default class Coder { @@ -27,28 +28,29 @@ export default class Coder generate(): string { let code = ''; - let previous: Token = new Token(TokenType.NOTHING, '', 0, 0); - - for (const current of this.#tokens) + + for (let index = 0; index < this.#tokens.length; index++) { - const prefix = this.#needsSpacingBefore(current, previous) ? ' ' : ''; - const postfix = this.#needsSpacingAfter(current) ? ' ' : ''; + const previous = this.#tokens[index - 1] ?? NO_TOKEN; + const current = this.#tokens[index]; + const next = this.#tokens[index + 1] ?? NO_TOKEN; + + const prefix = this.#needsSpacingBefore(previous, current) ? ' ' : ''; + const postfix = this.#needsSpacingAfter(current, next) ? ' ' : ''; code += `${prefix}${current.value}${postfix}`; - - previous = current; } return code; } - #needsSpacingBefore(current: Token, previous: Token): boolean + #needsSpacingBefore(previous: Token, current: Token): boolean { - if (current.isType(TokenType.KEYWORD) && this.#isInfixKeyword(current)) + if (current.isType(TokenType.KEYWORD) && this.#isTextType(previous)) { return true; } - else if (previous.isType(TokenType.OPERATOR) && current.isType(TokenType.OPERATOR)) + else if (current.isType(TokenType.OPERATOR) && previous.isType(TokenType.OPERATOR)) { return true; } @@ -56,33 +58,16 @@ export default class Coder return false; } - #needsSpacingAfter(current: Token): boolean - { - return current.isType(TokenType.KEYWORD) && this.#isPrefixKeyword(current); - } - - #isPrefixKeyword(token: Token): boolean + #needsSpacingAfter(current: Token, next: Token): boolean { - return this.#isInfixKeyword(token) - || token.hasValue(Keyword.VAR) - || token.hasValue(Keyword.LET) - || token.hasValue(Keyword.CONST) - || token.hasValue(Keyword.FUNCTION) - || token.hasValue(Keyword.CLASS) - || token.hasValue(Keyword.USING) - || token.hasValue(Keyword.RETURN) - || token.hasValue(Keyword.ASYNC) - || token.hasValue(Keyword.AWAIT) - || token.hasValue(Keyword.YIELD) - || token.hasValue(Keyword.NEW) - || token.hasValue(Keyword.THROW); + return current.isType(TokenType.KEYWORD) && (next.isType(TokenType.KEYWORD) || this.#isTextType(next)); } - #isInfixKeyword(token: Token): boolean + #isTextType(token: Token) { - return token.hasValue(Keyword.OF) - || token.hasValue(Keyword.IN) - || token.hasValue(Keyword.AS) - || token.hasValue(Keyword.FROM); + return token.isType(TokenType.IDENTIFIER) + || token.isType(TokenType.BOOLEAN) + || token.isType(TokenType.NOTHING) + || token.isType(TokenType.NUMBER); } } diff --git a/packages/analysis/src/static/definitions/TokenType.ts b/packages/analysis/src/static/definitions/TokenType.ts index 165cab04..c411231a 100644 --- a/packages/analysis/src/static/definitions/TokenType.ts +++ b/packages/analysis/src/static/definitions/TokenType.ts @@ -15,7 +15,8 @@ const TokenType = INDICATOR: 'indicator', REGEX: 'regex', SCOPE: 'scope', - WHITESPACE: 'whitespace' + WHITESPACE: 'whitespace', + NONE: 'none' }; export { TokenType }; diff --git a/packages/analysis/test/static/Parser.spec.ts b/packages/analysis/test/static/Parser.spec.ts index 03baff57..b7021d62 100644 --- a/packages/analysis/test/static/Parser.spec.ts +++ b/packages/analysis/test/static/Parser.spec.ts @@ -52,7 +52,7 @@ describe('Parser', () => { const expression = parser.parseStatement(VALUES.IF_ELSE); expect(expression).toBeInstanceOf(ESExpression); - expect(expression.toString(false)).toEqual('if(true){return "value1";}else{return "value2";}'); + expect(expression.toString(false)).toEqual('if(true){return"value1";}else{return"value2";}'); }); it('should parse an try...catch...finally expression', () => @@ -557,7 +557,7 @@ describe('Parser', () => expect(variable.binding).toBeInstanceOf(ESIdentifierBinding); expect(variable.type).toEqual('const'); expect(variable.initializer).toBeInstanceOf(ESExpression); - expect(variable.initializer?.toString(false)).toEqual(' as '); + expect(variable.initializer?.toString(false)).toEqual('as'); }); }); @@ -928,7 +928,7 @@ describe('Parser', () => expect(funktion.identifier).toEqual('name'); expect(funktion.isAsync).toBeFalsy(); - expect(funktion.body.toString()).toEqual("{return 'value';}"); + expect(funktion.body.toString()).toEqual("{return'value';}"); const parameters = funktion.parameters; expect(parameters).toHaveLength(0); @@ -940,7 +940,7 @@ describe('Parser', () => expect(funktion.identifier).toEqual('name'); expect(funktion.isAsync).toBeFalsy(); - expect(funktion.body.toString()).toEqual("{if(true){return 'value';}}"); + expect(funktion.body.toString()).toEqual("{if(true){return'value';}}"); const parameters = funktion.parameters; expect(parameters).toHaveLength(0); diff --git a/packages/analysis/test/static/fixtures/modules.fixture.ts b/packages/analysis/test/static/fixtures/modules.fixture.ts index 55d95543..43c0e7ce 100644 --- a/packages/analysis/test/static/fixtures/modules.fixture.ts +++ b/packages/analysis/test/static/fixtures/modules.fixture.ts @@ -82,7 +82,7 @@ export {Person}; class Person{#name;#age;constructor(name,age) {this.#name=name;this.#age=age;}} const peter=new Person(name,42); async function async(){} -const a=async ; +const a=async; const b=async ()=>{}; const as=12; export {as as hi}; From 632cfeb20303ab3d88a92118280c901d4e5473f2 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Fri, 5 Jun 2026 15:27:46 +0200 Subject: [PATCH 09/11] #787: plugin improvements --- packages/plugin-vite/src/index.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index 8e0d56a9..2c08a388 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -91,6 +91,7 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption return { name: 'jitar-plugin-vite', + enforce: 'pre', config() { @@ -112,6 +113,8 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption async buildStart() { + jitarImported = false; + const configurationManager = new ConfigurationManager(paths.project.root); if (pluginConfig.environmentFile !== undefined) @@ -138,12 +141,16 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption { return JITAR_BUNDLE_RESOLVE_ID; } + + return null; }, load(id) { if (id === JITAR_BUNDLE_RESOLVE_ID) { + jitarImported = true; + return createJitarBundle(middlewares, paths.vite.output!); } @@ -184,12 +191,10 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption const isFirstAppComponent = jitarImported === false && id.startsWith(paths.project.source!) - && (id.endsWith('.ts') || id.endsWith('.tsx')); + && (id.endsWith('.js') || id.endsWith('.ts') || id.endsWith('.jsx') || id.endsWith('.tsx')); if (isFirstAppComponent) { - jitarImported = true; - return `import '${JITAR_BUNDLE_ID}';\n${code}`; } From cc66aba59096b7cadab9c0a5ac635efd3f7b19a7 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Fri, 5 Jun 2026 16:15:35 +0200 Subject: [PATCH 10/11] #787: final touches --- documentation/docs/integrate/vite-plugin.md | 99 +-------------------- packages/plugin-vite/src/index.ts | 6 +- 2 files changed, 4 insertions(+), 101 deletions(-) diff --git a/documentation/docs/integrate/vite-plugin.md b/documentation/docs/integrate/vite-plugin.md index 4db2ba91..39d44bc1 100644 --- a/documentation/docs/integrate/vite-plugin.md +++ b/documentation/docs/integrate/vite-plugin.md @@ -15,101 +15,4 @@ next: For easy integration with popular frontend frameworks like React, Angular, Vue, etc. we provide a plugin for [Vite](https://vitejs.dev/){target="_blank"}. -::: tip -We think it's good to put all the frontend code in a separate folder for better separation of concerns. It also simplifies the build process. For this, we use the `webui` folder throughout the documentation. -::: - -::: info NOTE -We also provide a creator app with templates for the most used frameworks. We recommend checking this out first before using this plugin. More information can be found in [our quick start](../introduction/quick-start). -::: - -## Installation - -You can simply install the plugin as dev-dependency using NPM. - -```bash -npm install --save-dev @jitar/plugin-vite -``` - -Next it has to be added to the Vite config file. - -```ts -// vite.config.js -import jitar, { JitarConfig } from '@jitar/plugin-vite'; -import { defineConfig } from 'vite'; - -const JITAR_URL = 'http://localhost:3000'; -const JITAR_SEGMENTS = ['frontend']; -const JITAR_MIDDLEWARES = ['./requesterMiddleware']; - -const jitarConfig: JitarConfig = { - projectRoot: '../../', - sourceRoot: '../', - configurationFile: './jitar.json', - environmentFile: './dev.env', - jitarUrl: JITAR_URL, - segments: JITAR_SEGMENTS, - middleware: JITAR_MIDDLEWARES -}; - -export default defineConfig({ - publicDir: 'src/webui/public', - build: { - assetsDir: 'webui', - emptyOutDir: false - }, - plugins: [ - jitar(jitarConfig) - ] -}); -``` - -The plugin configuration has 5 parameters: - -1. projectRoot - The root directory of the the project relative to the Vite configuration. -1. sourceRoot - The source directory relative to the Vite configuration. -1. configurationFile - The Jitar configuration file relative to the project root. Jitar uses `./jitar.json` by default. -1. environmentFile - The environment file relative to the project root. Is only loaded when configured. -1. jitarUrl - The URL of the Jitar instance. Jitar uses by default `http://localhost:3000`, but can be configured differently. -1. segments - The segments to use for the client app. This is an array of strings. The default is an empty array. -1. middlewares - The middlewares to use for calling remote procedures. This is an array of strings. The default is an empty array. - -To build the segments, an additional tsconfig file is required to compile the source code. The configuration is also used to exclude the `webui` folder from the TypeScript compilation. - -```json -// tsconfig.jitar.json -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "noEmit": false, - "rootDir": "./src", - "outDir": "./dist" - }, - "include": ["src"], - "exclude": ["src/webui"] -} -``` - -Finally, the TypeScript compilation needs to be set as the last step in the package.json file. - -```json -{ - "build": "npm run build-domain && npm run build-webui", - "build-domain": "rm -rf dist && tsc -p tsconfig.jitar.json && jitar build", - "build-webui": "vite build", -} -``` - -::: tip -Checkout our demo project [Comify](https://github.com/MaskingTechnology/comify){target="_blank"} for a complete working setup. -::: - -## Usage - -For development you can run Vite as you would normally do. The only requirement is that an instance of Jitar must already run in the background. For production you can build the project and use Jitar as your web server. - -::: info IMPORTANT -Jitar currently doesn’t support hot reloads. This means that the Jitar server needs to get restarted every time the backend functions are created or updated. -::: +Documentation can be found on the [Jitar docs](https://docs.jitar.dev/integrate/vite-plugin.html). diff --git a/packages/plugin-vite/src/index.ts b/packages/plugin-vite/src/index.ts index 2c08a388..a39704a0 100644 --- a/packages/plugin-vite/src/index.ts +++ b/packages/plugin-vite/src/index.ts @@ -130,14 +130,14 @@ export default function viteJitar(pluginConfig: PluginConfig): PluginOption await buildHelper.readApplication(); }, - resolveId(source) + resolveId(id) { - if (source === JITAR_BUNDLE_ID) + if (id === JITAR_BUNDLE_ID) { return JITAR_BUNDLE_RESOLVE_ID; } - if (source === JITAR_SOURCE_ID) + if (id === JITAR_SOURCE_ID) { return JITAR_BUNDLE_RESOLVE_ID; } From f118fafdfcce0e6c9f7824777c3ee94323a2c8c4 Mon Sep 17 00:00:00 2001 From: Peter van Vliet Date: Fri, 5 Jun 2026 16:20:06 +0200 Subject: [PATCH 11/11] #787: updated vite version support --- packages/plugin-vite/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-vite/package.json b/packages/plugin-vite/package.json index b598ddae..d2a1f584 100644 --- a/packages/plugin-vite/package.json +++ b/packages/plugin-vite/package.json @@ -32,7 +32,7 @@ }, "peerDependencies": { "jitar": "^0.11.0", - "vite": ">=4.0.0 || >=5.0.0 || >=6.0.0 || >=7.0.0" + "vite": ">=7" }, "peerDependenciesMeta": { "vite": {