@codenotch/codenotch.cli 1.0.35 → 1.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/commands/generate/app.d.ts +2 -0
- package/dist/commands/generate/app.js +45 -0
- package/dist/commands/generate/app.js.map +1 -0
- package/dist/commands/generate/appmanifest.d.ts +2 -0
- package/dist/commands/generate/appmanifest.js +34 -0
- package/dist/commands/generate/appmanifest.js.map +1 -0
- package/dist/commands/generate/dbcontext.d.ts +2 -0
- package/dist/commands/generate/dbcontext.js +32 -0
- package/dist/commands/generate/dbcontext.js.map +1 -0
- package/dist/commands/generate/i18n.d.ts +2 -0
- package/dist/commands/generate/i18n.js +29 -0
- package/dist/commands/generate/i18n.js.map +1 -0
- package/dist/commands/generate/index.d.ts +2 -0
- package/dist/commands/generate/index.js +23 -0
- package/dist/commands/generate/index.js.map +1 -0
- package/dist/commands/generate/manifest.d.ts +2 -0
- package/dist/commands/generate/manifest.js +29 -0
- package/dist/commands/generate/manifest.js.map +1 -0
- package/dist/commands/generate/openapi.d.ts +2 -0
- package/dist/commands/generate/openapi.js +32 -0
- package/dist/commands/generate/openapi.js.map +1 -0
- package/dist/commands/generate/pkg.d.ts +2 -0
- package/dist/commands/generate/pkg.js +34 -0
- package/dist/commands/generate/pkg.js.map +1 -0
- package/dist/commands/generate/shared.d.ts +17 -0
- package/dist/commands/generate/shared.js +70 -0
- package/dist/commands/generate/shared.js.map +1 -0
- package/dist/commands/index.js +2 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/project/new.js +107 -187
- package/dist/commands/project/new.js.map +1 -1
- package/dist/commands/react/build.js +11 -5
- package/dist/commands/react/build.js.map +1 -1
- package/dist/commands/react/clean.d.ts +2 -0
- package/dist/commands/react/clean.js +46 -0
- package/dist/commands/react/clean.js.map +1 -0
- package/dist/commands/react/dev.d.ts +2 -0
- package/dist/commands/react/dev.js +27 -0
- package/dist/commands/react/dev.js.map +1 -0
- package/dist/commands/react/index.js +5 -1
- package/dist/commands/react/index.js.map +1 -1
- package/dist/commands/react/serve.js +33 -4
- package/dist/commands/react/serve.js.map +1 -1
- package/dist/commands/react/shared.d.ts +21 -0
- package/dist/commands/react/shared.js +80 -0
- package/dist/commands/react/shared.js.map +1 -0
- package/dist/commands/system/info.js +0 -7
- package/dist/commands/system/info.js.map +1 -1
- package/dist/commands/validation/ValidationUtils.d.ts +3 -13
- package/dist/commands/validation/ValidationUtils.js +5 -58
- package/dist/commands/validation/ValidationUtils.js.map +1 -1
- package/dist/commands/validation/files/AppManifestValidator.js +5 -20
- package/dist/commands/validation/files/AppManifestValidator.js.map +1 -1
- package/dist/commands/validation/files/I18nValidator.d.ts +24 -0
- package/dist/commands/validation/files/I18nValidator.js +190 -5
- package/dist/commands/validation/files/I18nValidator.js.map +1 -1
- package/dist/commands/validation/files/{BpmnValidator.d.ts → ProjectManifestValidator.d.ts} +1 -1
- package/dist/commands/validation/files/ProjectManifestValidator.js +31 -0
- package/dist/commands/validation/files/ProjectManifestValidator.js.map +1 -0
- package/dist/commands/validation/files/ScriptValidator.d.ts +6 -2
- package/dist/commands/validation/files/ScriptValidator.js +1 -1
- package/dist/commands/validation/files/ScriptValidator.js.map +1 -1
- package/dist/commands/validation/validate.js +15 -46
- package/dist/commands/validation/validate.js.map +1 -1
- package/dist/models/Codenotch.d.ts +0 -205
- package/dist/models/Codenotch.js +0 -211
- package/dist/models/Codenotch.js.map +1 -1
- package/dist/utils/BuildUtils.d.ts +66 -28
- package/dist/utils/BuildUtils.js +292 -330
- package/dist/utils/BuildUtils.js.map +1 -1
- package/dist/utils/ConsoleUtils.d.ts +13 -0
- package/dist/utils/ConsoleUtils.js +50 -0
- package/dist/utils/ConsoleUtils.js.map +1 -1
- package/dist/utils/DbSchemaUtils.d.ts +49 -0
- package/dist/utils/DbSchemaUtils.js +246 -0
- package/dist/utils/DbSchemaUtils.js.map +1 -0
- package/dist/utils/FileUtils.d.ts +104 -15
- package/dist/utils/FileUtils.js +285 -100
- package/dist/utils/FileUtils.js.map +1 -1
- package/dist/utils/GitHubAuthUtils.js.map +1 -1
- package/dist/utils/I18nTsUtils.d.ts +66 -0
- package/dist/utils/I18nTsUtils.js +221 -0
- package/dist/utils/I18nTsUtils.js.map +1 -0
- package/dist/utils/ManifestUtils.d.ts +24 -0
- package/dist/utils/ManifestUtils.js +53 -0
- package/dist/utils/ManifestUtils.js.map +1 -0
- package/dist/utils/OpenApiUtils.d.ts +81 -0
- package/dist/utils/OpenApiUtils.js +123 -0
- package/dist/utils/OpenApiUtils.js.map +1 -0
- package/dist/utils/ProjectCompilationUtils.d.ts +3 -30
- package/dist/utils/ProjectCompilationUtils.js +26 -760
- package/dist/utils/ProjectCompilationUtils.js.map +1 -1
- package/dist/utils/ProjectGeneratorUtils.d.ts +35 -0
- package/dist/utils/ProjectGeneratorUtils.js +119 -0
- package/dist/utils/ProjectGeneratorUtils.js.map +1 -0
- package/dist/utils/ProjectTemplates.d.ts +102 -0
- package/dist/utils/ProjectTemplates.js +284 -0
- package/dist/utils/ProjectTemplates.js.map +1 -0
- package/dist/utils/ProjectUtils.d.ts +217 -4
- package/dist/utils/ProjectUtils.js +386 -50
- package/dist/utils/ProjectUtils.js.map +1 -1
- package/dist/utils/RuntimeUtils.js +14 -8
- package/dist/utils/RuntimeUtils.js.map +1 -1
- package/dist/utils/ScriptDeclarationUtils.d.ts +169 -0
- package/dist/utils/ScriptDeclarationUtils.js +398 -0
- package/dist/utils/ScriptDeclarationUtils.js.map +1 -0
- package/dist/utils/ServeUtils.d.ts +0 -1
- package/dist/utils/ServeUtils.js +11 -29
- package/dist/utils/ServeUtils.js.map +1 -1
- package/dist/utils/ShellUtils.d.ts +6 -0
- package/dist/utils/ShellUtils.js +13 -0
- package/dist/utils/ShellUtils.js.map +1 -1
- package/dist/utils/TemplateUtils.d.ts +62 -0
- package/dist/utils/TemplateUtils.js +218 -0
- package/dist/utils/TemplateUtils.js.map +1 -0
- package/dist/utils/TypeSchemaUtils.d.ts +42 -0
- package/dist/utils/TypeSchemaUtils.js +171 -0
- package/dist/utils/TypeSchemaUtils.js.map +1 -0
- package/package.json +3 -3
- package/dist/commands/validation/files/BpmnValidator.js +0 -32
- package/dist/commands/validation/files/BpmnValidator.js.map +0 -1
- package/dist/commands/validation/files/DbSchemaValidator.d.ts +0 -5
- package/dist/commands/validation/files/DbSchemaValidator.js +0 -16
- package/dist/commands/validation/files/DbSchemaValidator.js.map +0 -1
- package/dist/commands/validation/files/DocumentValidator.d.ts +0 -5
- package/dist/commands/validation/files/DocumentValidator.js +0 -12
- package/dist/commands/validation/files/DocumentValidator.js.map +0 -1
- package/dist/commands/validation/files/ManifestCacheValidator.d.ts +0 -5
- package/dist/commands/validation/files/ManifestCacheValidator.js +0 -121
- package/dist/commands/validation/files/ManifestCacheValidator.js.map +0 -1
- package/dist/commands/validation/files/ManifestValidator.d.ts +0 -5
- package/dist/commands/validation/files/ManifestValidator.js +0 -14
- package/dist/commands/validation/files/ManifestValidator.js.map +0 -1
- package/dist/commands/validation/files/TableValidator.d.ts +0 -5
- package/dist/commands/validation/files/TableValidator.js +0 -19
- package/dist/commands/validation/files/TableValidator.js.map +0 -1
- package/dist/models/DbModels.d.ts +0 -221
- package/dist/models/DbModels.js +0 -130
- package/dist/models/DbModels.js.map +0 -1
- package/dist/models/OpenApiModels.d.ts +0 -115
- package/dist/models/OpenApiModels.js +0 -103
- package/dist/models/OpenApiModels.js.map +0 -1
- package/dist/utils/I18nUtils.d.ts +0 -9
- package/dist/utils/I18nUtils.js +0 -54
- package/dist/utils/I18nUtils.js.map +0 -1
- package/dist/utils/OpenAPIUtils.d.ts +0 -33
- package/dist/utils/OpenAPIUtils.js +0 -279
- package/dist/utils/OpenAPIUtils.js.map +0 -1
package/dist/utils/BuildUtils.js
CHANGED
|
@@ -4,18 +4,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
|
+
const path_1 = require("path");
|
|
7
8
|
const StringUtils_1 = __importDefault(require("./StringUtils"));
|
|
8
9
|
const FileUtils_1 = __importDefault(require("./FileUtils"));
|
|
9
10
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
11
|
const fs_2 = __importDefault(require("fs"));
|
|
11
12
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
-
const I18nUtils_1 = __importDefault(require("./I18nUtils"));
|
|
13
|
-
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
14
13
|
const ShellUtils_1 = __importDefault(require("./ShellUtils"));
|
|
15
|
-
const os_1 = require("os");
|
|
16
14
|
const ConsoleUtils_1 = __importDefault(require("./ConsoleUtils"));
|
|
17
15
|
class BuildUtils {
|
|
18
|
-
static CN_REACT_VERSION = '2.0.
|
|
16
|
+
static CN_REACT_VERSION = '2.0.1';
|
|
19
17
|
static findWorkspaceFromFile(childPath) {
|
|
20
18
|
let parts = childPath.split(FileUtils_1.default.slash());
|
|
21
19
|
parts = parts.slice(0, parts.length - 1); // Remove file name
|
|
@@ -31,20 +29,47 @@ class BuildUtils {
|
|
|
31
29
|
return workspacePath;
|
|
32
30
|
}
|
|
33
31
|
/**
|
|
34
|
-
*
|
|
32
|
+
* Builds one React app of a Codenotch project into a ready-to-serve bundle.
|
|
33
|
+
* Behind the command: cn react build <target_file>
|
|
34
|
+
*
|
|
35
|
+
* Everything is staged under the `.codenotch/` folder of the workspace, the sources of the
|
|
36
|
+
* project are never touched:
|
|
37
|
+
* - `.codenotch/<appName>-source` — the Vite project: generated package.json, index.html,
|
|
38
|
+
* index.jsx (mounts the app component with react 19's createRoot), vite.config.mjs,
|
|
39
|
+
* tsconfig.json, the workspace `.npmrc` when there is one, and a copy of every source file of the workspace,
|
|
40
|
+
* mirrored flat so that root config files (postcss.config.js, ...) stay where Vite looks.
|
|
41
|
+
* - `.codenotch/<appName>-dist` — the bundle Vite emits, plus a `.env` holding the Codenotch
|
|
42
|
+
* environment (app name, manifests, cluster url) read by the served page.
|
|
43
|
+
* Both folders are deleted first when a previous build left them behind.
|
|
44
|
+
*
|
|
45
|
+
* The build itself runs `npm install` then `npm run build` (vite alone: the copy holds server
|
|
46
|
+
* files too, typechecking is the job of 'cn validate') inside `-source`, with the Node the CLI
|
|
47
|
+
* runs under — Node 20 or newer is expected (Vite 8), and npm needs the network.
|
|
48
|
+
*
|
|
49
|
+
* On success, prints the `cn react serve '<dist>'` command to try the bundle.
|
|
50
|
+
*
|
|
51
|
+
* @param appFilePath Path (absolute, or relative to the current directory) to the app
|
|
52
|
+
* component, e.g. `./apps/index.tsx`. NOT the manifest: the sibling
|
|
53
|
+
* `<name>.manifest.json` is derived from it, and must exist and declare
|
|
54
|
+
* `app.name`, which names the staging folders. The file must live inside
|
|
55
|
+
* a Codenotch workspace (a `manifest.json` in one of its parent folders).
|
|
56
|
+
* @param clusterUrl Base URL of the Codenotch cluster the bundle will talk to, written into
|
|
57
|
+
* the `.env` of the dist. Without it the bundle is built all the same,
|
|
58
|
+
* but not bound to a cluster.
|
|
59
|
+
*
|
|
60
|
+
* Validation failures (missing file, no workspace, no app name...) print the reason and leave
|
|
61
|
+
* with `process.exit(1)`: this method is the command, not a library call. See `buildApp2` for
|
|
62
|
+
* the throwing, CI oriented variant.
|
|
35
63
|
*/
|
|
36
|
-
static async
|
|
64
|
+
static async buildReactApp(appFilePath, clusterUrl) {
|
|
37
65
|
//appFilePath = '/home/fabian/Documents/Scenario/test-with-jsx/apps/AppWithFC.tsx';
|
|
38
66
|
//clusterUrl = 'https://fabric.echino.com:19081/lemollqa/scenario';
|
|
39
67
|
if (`${appFilePath ?? ''}`.trim() === '') {
|
|
40
68
|
console.log(chalk_1.default.red(`Error: No target file provided for build command.`));
|
|
41
69
|
process.exit(1);
|
|
42
70
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
let currentPath = process.cwd();
|
|
46
|
-
appFilePath = StringUtils_1.default.normalizePath(`${currentPath}/${appFilePath}`);
|
|
47
|
-
}
|
|
71
|
+
// resolve() already turns a relative path into an absolute one, based on the current directory
|
|
72
|
+
appFilePath = StringUtils_1.default.normalizePath((0, path_1.resolve)(appFilePath));
|
|
48
73
|
// Check arguments
|
|
49
74
|
if ((0, fs_1.existsSync)(appFilePath ?? '') === false) {
|
|
50
75
|
console.log(chalk_1.default.red(`Error: File "${appFilePath}" not found`));
|
|
@@ -55,8 +80,6 @@ class BuildUtils {
|
|
|
55
80
|
console.log(chalk_1.default.red(`Error: Could not find workspace manifest for file "${appFilePath}".`));
|
|
56
81
|
process.exit(1);
|
|
57
82
|
}
|
|
58
|
-
// Tenant name
|
|
59
|
-
let tenantName = await this.fetchTenantName(clusterUrl);
|
|
60
83
|
// Load workspace
|
|
61
84
|
console.log("Loading workspace manifest...");
|
|
62
85
|
let workspace = {
|
|
@@ -75,23 +98,25 @@ class BuildUtils {
|
|
|
75
98
|
process.exit(1);
|
|
76
99
|
}
|
|
77
100
|
let appManifest = JSON.parse(appManifestContent);
|
|
78
|
-
let appName = `${appManifest.
|
|
101
|
+
let appName = `${appManifest.app?.name ?? ''}`.trim();
|
|
79
102
|
if (appName === '') {
|
|
80
103
|
console.log(chalk_1.default.red(`Error: App name not found in manifest at "${appManifestPath}"\n`));
|
|
81
104
|
process.exit(1);
|
|
82
105
|
}
|
|
83
106
|
ConsoleUtils_1.default.check(`App manifest loaded successfully (App name: "${appName}").\n`);
|
|
84
107
|
// Define paths
|
|
108
|
+
// The workspace layout is mirrored directly under outDir (no 'src/' wrapper), so root
|
|
109
|
+
// config files (postcss.config.js, tailwind, ...) land where Vite looks for them
|
|
85
110
|
let outDir = StringUtils_1.default.normalizePath(`${workspacePath}/.codenotch/${appName}-source`);
|
|
86
111
|
let distDir = StringUtils_1.default.normalizePath(`${workspacePath}/.codenotch/${appName}-dist`);
|
|
87
112
|
let fileName = StringUtils_1.default.firstUpper(StringUtils_1.default.getNameWithoutExtention(appFilename));
|
|
88
|
-
let outFilePath = StringUtils_1.default.normalizePath(`${appFilePath.replace(workspacePath, outDir
|
|
113
|
+
let outFilePath = StringUtils_1.default.normalizePath(`${appFilePath.replace(workspacePath, outDir)}`);
|
|
89
114
|
let relativeOutFilePath = StringUtils_1.default.toRelativePath(outFilePath, outDir).replaceAll('\\', '/');
|
|
90
115
|
// Clean previous builds
|
|
91
116
|
if ((0, fs_1.existsSync)(outDir) || (0, fs_1.existsSync)(distDir)) {
|
|
92
117
|
console.log("Cleaning previous builds...");
|
|
93
|
-
FileUtils_1.default.
|
|
94
|
-
FileUtils_1.default.
|
|
118
|
+
FileUtils_1.default.deleteRecursively(outDir);
|
|
119
|
+
FileUtils_1.default.deleteRecursively(distDir);
|
|
95
120
|
ConsoleUtils_1.default.check(`Output directory cleaned (${outDir})\n`);
|
|
96
121
|
}
|
|
97
122
|
console.log("Creating build files...");
|
|
@@ -107,16 +132,12 @@ class BuildUtils {
|
|
|
107
132
|
let indexJsx = this.createIndexJsx(relativeOutFilePath, fileName);
|
|
108
133
|
FileUtils_1.default.writeFileSync(outDir + '/index.jsx', indexJsx);
|
|
109
134
|
ConsoleUtils_1.default.check(`index.jsx created successfully`);
|
|
110
|
-
// vite.config.
|
|
135
|
+
// vite.config.mjs (.mjs so it always loads as ESM, regardless of package.json "type")
|
|
111
136
|
let viteConfig = this.createViteConfig(appName);
|
|
112
|
-
FileUtils_1.default.writeFileSync(outDir + '/vite.config.
|
|
113
|
-
ConsoleUtils_1.default.check(`vite.config.
|
|
114
|
-
//
|
|
115
|
-
let
|
|
116
|
-
FileUtils_1.default.writeFileSync(outDir + '/empty-module.js', emptyModule);
|
|
117
|
-
ConsoleUtils_1.default.check(`empty-module.js created successfully`);
|
|
118
|
-
// tsconfig.json
|
|
119
|
-
let tsconfig = this.createTsConfig();
|
|
137
|
+
FileUtils_1.default.writeFileSync(outDir + '/vite.config.mjs', viteConfig);
|
|
138
|
+
ConsoleUtils_1.default.check(`vite.config.mjs created successfully`);
|
|
139
|
+
// tsconfig.json - layout is flat (mirrors the workspace), so typecheck the source trees
|
|
140
|
+
let tsconfig = this.createTsConfig(["**/*.ts", "**/*.tsx"]);
|
|
120
141
|
FileUtils_1.default.writeFileSync(outDir + '/tsconfig.json', tsconfig);
|
|
121
142
|
ConsoleUtils_1.default.check(`tsconfig.json created successfully`);
|
|
122
143
|
let npmRcContent = fs_2.default.existsSync(StringUtils_1.default.normalizePath(`${workspacePath}/.npmrc`)) ?
|
|
@@ -129,48 +150,42 @@ class BuildUtils {
|
|
|
129
150
|
// Find files to copy
|
|
130
151
|
console.log("\n");
|
|
131
152
|
console.log("Reading files...");
|
|
132
|
-
let
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
}
|
|
153
|
+
let includedFiles = FileUtils_1.default.listFilesRecursively(workspacePath, {
|
|
154
|
+
fileExtensions: ['.css', '.scss', '.tsx', '.jsx', '.ts', '.js', '.cjs', '.mjs'],
|
|
155
|
+
// Without these the copy would swallow the dependencies, and the staging folder itself
|
|
156
|
+
ignoredFolderNames: ['.codenotch', 'node_modules', '.git']
|
|
157
|
+
});
|
|
139
158
|
if (includedFiles.length === 0) {
|
|
140
159
|
console.log(chalk_1.default.red(`Error: No files found in "${workspacePath}" to include in the build`));
|
|
141
160
|
return;
|
|
142
161
|
}
|
|
143
162
|
for (let includedFile of includedFiles) {
|
|
144
|
-
let targetPath = StringUtils_1.default.normalizePath(`${includedFile.replace(workspacePath, outDir
|
|
163
|
+
let targetPath = StringUtils_1.default.normalizePath(`${includedFile.replace(workspacePath, outDir)}`);
|
|
145
164
|
fs_extra_1.default.copySync(includedFile, targetPath);
|
|
146
165
|
}
|
|
147
166
|
ConsoleUtils_1.default.check(`${includedFiles.length} files copied successfully\n`);
|
|
148
167
|
// execute npm i in the outDir
|
|
149
168
|
await ShellUtils_1.default.exec(outDir, 'npm install', 'Installing dependencies', true);
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
169
|
+
// Vite 8 needs Node 20+: warn up front, its own error would be cryptic
|
|
170
|
+
const nodeMajor = parseInt(process.versions.node.split('.')[0], 10);
|
|
171
|
+
if (nodeMajor < 20) {
|
|
172
|
+
ConsoleUtils_1.default.checkWarning(`Node ${process.versions.node} detected, the build needs Node 20 or newer and may fail.`);
|
|
153
173
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}
|
|
157
|
-
ConsoleUtils_1.default.check(`Nvm and build executed successfully\n`);
|
|
174
|
+
await ShellUtils_1.default.exec(outDir, 'npm run build', 'Building project', true);
|
|
175
|
+
ConsoleUtils_1.default.check(`Build executed successfully\n`);
|
|
158
176
|
// create .env file
|
|
159
177
|
console.log("Creating .env file...");
|
|
160
178
|
let envVariables = await this.getCodenotchEnvVariables(workspace, {
|
|
161
179
|
appName: appName,
|
|
162
180
|
app: appManifest,
|
|
163
|
-
tenantName: tenantName,
|
|
164
181
|
clusterUrl: clusterUrl
|
|
165
182
|
});
|
|
166
|
-
|
|
183
|
+
// A variable without value is left out, otherwise the page would read the string "undefined"
|
|
184
|
+
let envContent = Object.keys(envVariables)
|
|
185
|
+
.filter(c => envVariables[c] !== undefined && envVariables[c] !== null)
|
|
186
|
+
.map(c => `${c}=${envVariables[c]}`).join('\n');
|
|
167
187
|
FileUtils_1.default.writeFileSync(distDir + '/.env', envContent);
|
|
168
188
|
ConsoleUtils_1.default.check(`.env file created successfully\n`);
|
|
169
|
-
// create auml.json file
|
|
170
|
-
console.log("Creating auml.json file...");
|
|
171
|
-
let aumlJson = JSON.stringify(this.getAumlVariables(workspace, tenantName, clusterUrl), null, 4);
|
|
172
|
-
FileUtils_1.default.writeFileSync(distDir + '/auml.json', aumlJson);
|
|
173
|
-
ConsoleUtils_1.default.check(`auml.json file created successfully\n`);
|
|
174
189
|
let bundlePath = StringUtils_1.default.normalizePath(`${distDir}`);
|
|
175
190
|
console.log('');
|
|
176
191
|
console.log(chalk_1.default.green(`Build completed!\n`));
|
|
@@ -183,17 +198,14 @@ class BuildUtils {
|
|
|
183
198
|
// Joé:
|
|
184
199
|
// Temporary minimal method to build React app to package and deploy the project, not sure if should replaced the current build or not
|
|
185
200
|
// Should work in CI/CD
|
|
186
|
-
// Doesn't create .env
|
|
201
|
+
// Doesn't create .env, assume we are using the correct Node version
|
|
187
202
|
// Create/delete files, assume it's working in copy of the project
|
|
188
203
|
// In this method, caller is responsible for having Node 20 installed and ready
|
|
189
204
|
if (`${appFilePath ?? ''}`.trim() === '') {
|
|
190
205
|
throw new Error(`No target file provided for build command.`);
|
|
191
206
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
let currentPath = process.cwd();
|
|
195
|
-
appFilePath = StringUtils_1.default.normalizePath(`${currentPath}/${appFilePath}`);
|
|
196
|
-
}
|
|
207
|
+
// resolve() already turns a relative path into an absolute one, based on the current directory
|
|
208
|
+
appFilePath = StringUtils_1.default.normalizePath((0, path_1.resolve)(appFilePath));
|
|
197
209
|
// Check arguments
|
|
198
210
|
if ((0, fs_1.existsSync)(appFilePath ?? '') === false) {
|
|
199
211
|
throw new Error(`File "${appFilePath}" not found`);
|
|
@@ -211,7 +223,7 @@ class BuildUtils {
|
|
|
211
223
|
throw new Error(`App manifest file not found at "${appManifestPath}"`);
|
|
212
224
|
}
|
|
213
225
|
let appManifest = JSON.parse(appManifestContent);
|
|
214
|
-
let appName = `${appManifest.
|
|
226
|
+
let appName = `${appManifest.app?.name ?? ''}`.trim();
|
|
215
227
|
if (appName === '') {
|
|
216
228
|
throw new Error(`App name not found in manifest at "${appManifestPath}"`);
|
|
217
229
|
}
|
|
@@ -236,9 +248,6 @@ class BuildUtils {
|
|
|
236
248
|
// vite.config.mjs (.mjs so it always loads as ESM, regardless of package.json "type")
|
|
237
249
|
let viteConfig = this.createViteConfig(appName);
|
|
238
250
|
FileUtils_1.default.writeFileSync(outDir + '/vite.config.mjs', viteConfig);
|
|
239
|
-
// empty-module.js , needed to mock some modules crypto-browserify -> can we avoid this ?
|
|
240
|
-
let emptyModule = this.createEmptyModule();
|
|
241
|
-
FileUtils_1.default.writeFileSync(outDir + '/empty-module.js', emptyModule);
|
|
242
251
|
// tsconfig.json — layout is flat (mirrors the workspace), so typecheck the source trees
|
|
243
252
|
let tsconfig = this.createTsConfig(["**/*.ts", "**/*.tsx"]);
|
|
244
253
|
FileUtils_1.default.writeFileSync(outDir + '/tsconfig.json', tsconfig);
|
|
@@ -250,18 +259,10 @@ class BuildUtils {
|
|
|
250
259
|
}
|
|
251
260
|
// Find files to copy
|
|
252
261
|
//TODO what if we have 2 apps in the /apps folder ? if we build one it will copy the file from the other as they are not separated in different folders
|
|
253
|
-
let
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
let normalized = file.replaceAll('\\', '/');
|
|
258
|
-
if (normalized.includes('/.codenotch/') || normalized.includes('/node_modules/')) {
|
|
259
|
-
continue;
|
|
260
|
-
}
|
|
261
|
-
if (includedExts.some(ext => file.toLowerCase().endsWith(ext))) {
|
|
262
|
-
includedFiles.push(file);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
262
|
+
let includedFiles = FileUtils_1.default.listFilesRecursively(workspacePath, {
|
|
263
|
+
fileExtensions: ['.css', '.scss', '.tsx', '.jsx', '.ts', '.js', '.cjs', '.mjs'],
|
|
264
|
+
ignoredFolderNames: ['.codenotch', 'node_modules']
|
|
265
|
+
});
|
|
265
266
|
if (includedFiles.length === 0) {
|
|
266
267
|
throw new Error(`No files found in "${workspacePath}" to include in the build`);
|
|
267
268
|
}
|
|
@@ -286,67 +287,49 @@ class BuildUtils {
|
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
289
|
static createIndexJsx(relativeOutFilePath, fileName) {
|
|
289
|
-
return `
|
|
290
|
-
import
|
|
291
|
-
import
|
|
292
|
-
import
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
.then(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
290
|
+
return `
|
|
291
|
+
import { createRoot } from 'react-dom/client';
|
|
292
|
+
import ${fileName} from './${relativeOutFilePath}';
|
|
293
|
+
import { init } from '@codenotch/codenotch.react';
|
|
294
|
+
|
|
295
|
+
// The environment is exposed by the server hosting the bundle (see 'cn react serve')
|
|
296
|
+
const root = createRoot(document.getElementById('root'));
|
|
297
|
+
fetch('/api/env')
|
|
298
|
+
.then(response => response.json())
|
|
299
|
+
.then(data => {
|
|
300
|
+
init(data);
|
|
301
|
+
root.render(<${fileName} />);
|
|
302
|
+
})
|
|
303
|
+
.catch(error => {
|
|
304
|
+
console.error('Error fetching environment variables:', error);
|
|
305
|
+
init({});
|
|
306
|
+
root.render(<${fileName} />);
|
|
307
|
+
});
|
|
306
308
|
`.trim();
|
|
307
309
|
}
|
|
308
310
|
/**
|
|
309
311
|
* When served from the runtime env variables are not available, the variables are injected into the html file instead
|
|
310
312
|
*/
|
|
311
313
|
static createIndexJsxDeployment(relativeOutFilePath, fileName) {
|
|
312
|
-
return `
|
|
313
|
-
import
|
|
314
|
-
import
|
|
315
|
-
import
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
330
|
-
|
|
314
|
+
return `
|
|
315
|
+
import { createRoot } from 'react-dom/client';
|
|
316
|
+
import ${fileName} from './${relativeOutFilePath}';
|
|
317
|
+
import { init } from '@codenotch/codenotch.react';
|
|
318
|
+
|
|
319
|
+
// variables are injected into the html by the runtime, we can access them on the window object
|
|
320
|
+
const data = {
|
|
321
|
+
clusterUrl: tenant.clusterUrl,
|
|
322
|
+
serviceName: serviceName,
|
|
323
|
+
theme: 'dark',
|
|
324
|
+
language: languages[0] ?? 'en',
|
|
325
|
+
appManifest: appManifest,
|
|
326
|
+
appName: appName
|
|
327
|
+
};
|
|
328
|
+
init(data);
|
|
329
|
+
createRoot(document.getElementById('root')).render(<${fileName} />);
|
|
330
|
+
|
|
331
331
|
`.trim();
|
|
332
332
|
}
|
|
333
|
-
static async fetchTenantName(clusterUrl) {
|
|
334
|
-
let tenantName = undefined;
|
|
335
|
-
if (clusterUrl !== undefined) {
|
|
336
|
-
console.log('Fetching tenant name from cluster URL...');
|
|
337
|
-
tenantName = await this.getTenantName(clusterUrl);
|
|
338
|
-
if (tenantName) {
|
|
339
|
-
ConsoleUtils_1.default.check(`Tenant name "${tenantName}" fetched successfully\n`);
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
console.log(chalk_1.default.yellow(`Warning: Unable to fetch tenant name from cluster URL "${clusterUrl}".\n`));
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
else {
|
|
346
|
-
console.log(chalk_1.default.yellow(`Warning: No cluster URL provided.\n`));
|
|
347
|
-
}
|
|
348
|
-
return tenantName;
|
|
349
|
-
}
|
|
350
333
|
static async getCodenotchEnvVariables(workpace, options) {
|
|
351
334
|
let result = {
|
|
352
335
|
clusterUrl: options.clusterUrl,
|
|
@@ -358,41 +341,14 @@ ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
|
358
341
|
if (options.app) {
|
|
359
342
|
result.appManifest = JSON.stringify(options.app);
|
|
360
343
|
}
|
|
361
|
-
if (options.tenantName) {
|
|
362
|
-
result.tenantName = options.tenantName;
|
|
363
|
-
}
|
|
364
|
-
let tenantName = options.tenantName;
|
|
365
|
-
if (tenantName)
|
|
366
|
-
result.tenantName = tenantName;
|
|
367
344
|
if (options.appName)
|
|
368
345
|
result.appName = options.appName;
|
|
369
346
|
if (options.accessToken)
|
|
370
347
|
result.accessToken = options.accessToken;
|
|
371
348
|
if (options.baseUrl)
|
|
372
349
|
result.baseUrl = options.baseUrl;
|
|
373
|
-
if (workpace) {
|
|
374
|
-
let allI18nValues = await I18nUtils_1.default.getAllI18nFiles(workpace.path);
|
|
375
|
-
for (let allI18nValue of allI18nValues) {
|
|
376
|
-
for (let langValue of allI18nValue.values) {
|
|
377
|
-
result[`i18n.${allI18nValue.key}.${langValue.lang}`] = JSON.stringify(langValue.value);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
350
|
return result;
|
|
382
351
|
}
|
|
383
|
-
static async getTenantName(cluster) {
|
|
384
|
-
try {
|
|
385
|
-
let obj = await (await (0, node_fetch_1.default)(`${cluster}/portal/tenant`)).json();
|
|
386
|
-
if (obj && obj.name && typeof obj.name === 'string') {
|
|
387
|
-
return obj.name;
|
|
388
|
-
}
|
|
389
|
-
return undefined;
|
|
390
|
-
}
|
|
391
|
-
catch (e) {
|
|
392
|
-
console.error("Error while fetching tenant name:", e);
|
|
393
|
-
return undefined;
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
352
|
/** Compiler options shared by the generated build tsconfig and `cn validate` on script files. */
|
|
397
353
|
static defaultCompilerOptions() {
|
|
398
354
|
return {
|
|
@@ -405,11 +361,11 @@ ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
|
405
361
|
"strict": true,
|
|
406
362
|
"forceConsistentCasingInFileNames": true,
|
|
407
363
|
"module": "ESNext",
|
|
408
|
-
"moduleResolution": "
|
|
364
|
+
"moduleResolution": "Bundler",
|
|
409
365
|
"resolveJsonModule": true,
|
|
410
366
|
"isolatedModules": true,
|
|
411
367
|
"noEmit": true, // On demande à tsc de ne PAS générer de fichiers
|
|
412
|
-
"jsx": "react" //
|
|
368
|
+
"jsx": "react-jsx" // automatic runtime, the react 19 default
|
|
413
369
|
};
|
|
414
370
|
}
|
|
415
371
|
static createTsConfig(include = ["src"]) {
|
|
@@ -419,97 +375,46 @@ ReactDOM.render(<${fileName} />, document.getElementById('root'));
|
|
|
419
375
|
}, null, 4);
|
|
420
376
|
return tsconfig;
|
|
421
377
|
}
|
|
422
|
-
static createEmptyModule() {
|
|
423
|
-
let emptyModule = `
|
|
424
|
-
const deepMock = new Proxy(() => null, {
|
|
425
|
-
get: (target, prop) => {
|
|
426
|
-
console.warn('Empty module proxy accessed property: ', prop);
|
|
427
|
-
if (prop === '__esModule') return true;
|
|
428
|
-
return deepMock;
|
|
429
|
-
}
|
|
430
|
-
});
|
|
431
|
-
export default deepMock;
|
|
432
|
-
export class ComponentDescription {
|
|
433
|
-
constructor() {
|
|
434
|
-
this.tag = '';
|
|
435
|
-
this.props = {};
|
|
436
|
-
this.parentInheritedProps = {};
|
|
437
|
-
this.children = [];
|
|
438
|
-
this.storedData = {};
|
|
439
|
-
}
|
|
440
|
-
};
|
|
441
|
-
export const DeclarationState = {
|
|
442
|
-
IDLE : "idle",
|
|
443
|
-
LOADING : "loading",
|
|
444
|
-
SUCCESS : "success",
|
|
445
|
-
ERROR : "error"
|
|
446
|
-
};
|
|
447
|
-
export const DspVarType = {
|
|
448
|
-
STRING : "string",
|
|
449
|
-
BOOLEAN : "boolean",
|
|
450
|
-
NUMBER : "number",
|
|
451
|
-
INTEGER : "integer",
|
|
452
|
-
COLOR : "color",
|
|
453
|
-
THICKNESS : "thickness",
|
|
454
|
-
SIZE : "size",
|
|
455
|
-
BORDER : "border",
|
|
456
|
-
OBJECT : "object",
|
|
457
|
-
ARRAY : "array",
|
|
458
|
-
FUNCTION : "function",
|
|
459
|
-
ACTION : "action",
|
|
460
|
-
REACT_NODE : "reactNode",
|
|
461
|
-
RENDERER : "renderer"
|
|
462
|
-
};`.trim();
|
|
463
|
-
return emptyModule;
|
|
464
|
-
}
|
|
465
378
|
static createViteConfig(appName) {
|
|
466
|
-
let debugOptions = `
|
|
467
|
-
sourcemap: true,
|
|
468
|
-
terserOptions: {
|
|
469
|
-
mangle: false,
|
|
470
|
-
keep_fnames: true,
|
|
471
|
-
keep_classnames: true,
|
|
379
|
+
let debugOptions = `
|
|
380
|
+
sourcemap: true,
|
|
381
|
+
terserOptions: {
|
|
382
|
+
mangle: false,
|
|
383
|
+
keep_fnames: true,
|
|
384
|
+
keep_classnames: true,
|
|
472
385
|
}`;
|
|
473
|
-
let viteConfig = `
|
|
474
|
-
import { defineConfig } from 'vite'
|
|
475
|
-
import react from '@vitejs/plugin-react'
|
|
476
|
-
import path from 'path';
|
|
477
|
-
export default defineConfig({
|
|
478
|
-
plugins: [
|
|
479
|
-
react(
|
|
480
|
-
],
|
|
481
|
-
base: './',
|
|
482
|
-
build: {
|
|
483
|
-
outDir: '../${appName}-dist',
|
|
484
|
-
emptyOutDir: true,
|
|
485
|
-
${debugOptions}
|
|
486
|
-
}
|
|
487
|
-
resolve: {
|
|
488
|
-
alias: [
|
|
489
|
-
{ find: 'crypto-browserify', replacement: './empty-module.js' },
|
|
490
|
-
{ find: /^@echino\\/codenotch\\.ui\\.monaco(\\/.*)?$/, replacement: path.resolve(__dirname, './empty-module.js') },
|
|
491
|
-
{ find: /^@echino\\/echino\\.ui\\.sdk(\\/.*)?$/, replacement: path.resolve(__dirname, './empty-module.js') },
|
|
492
|
-
],
|
|
493
|
-
},
|
|
386
|
+
let viteConfig = `
|
|
387
|
+
import { defineConfig } from 'vite'
|
|
388
|
+
import react from '@vitejs/plugin-react'
|
|
389
|
+
import path from 'path';
|
|
390
|
+
export default defineConfig({
|
|
391
|
+
plugins: [
|
|
392
|
+
react(),
|
|
393
|
+
],
|
|
394
|
+
base: './',
|
|
395
|
+
build: {
|
|
396
|
+
outDir: '../${appName}-dist',
|
|
397
|
+
emptyOutDir: true,
|
|
398
|
+
${debugOptions}
|
|
399
|
+
}
|
|
494
400
|
})`.trim();
|
|
495
401
|
return viteConfig;
|
|
496
402
|
}
|
|
497
403
|
static createIndexHtml(appManifest, appName) {
|
|
498
|
-
let indexHtml = `<!DOCTYPE html>
|
|
499
|
-
<html lang="fr">
|
|
500
|
-
<head>
|
|
501
|
-
<meta charset="${appManifest.html?.charset ?? 'UTF-8'}" />
|
|
502
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
503
|
-
<title>${appManifest.html?.title ?? appName}</title>
|
|
504
|
-
<meta name="description" content="${appManifest.html?.description ?? ''}" />
|
|
505
|
-
<meta name="author" content="${appManifest.html?.author ?? ''}" />
|
|
506
|
-
<meta name="keywords" content="${appManifest.html?.keywords ?? ''}" />
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
<
|
|
511
|
-
|
|
512
|
-
</body>
|
|
404
|
+
let indexHtml = `<!DOCTYPE html>
|
|
405
|
+
<html lang="fr">
|
|
406
|
+
<head>
|
|
407
|
+
<meta charset="${appManifest.html?.charset ?? 'UTF-8'}" />
|
|
408
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
409
|
+
<title>${appManifest.html?.title ?? appName}</title>
|
|
410
|
+
<meta name="description" content="${appManifest.html?.description ?? ''}" />
|
|
411
|
+
<meta name="author" content="${appManifest.html?.author ?? ''}" />
|
|
412
|
+
<meta name="keywords" content="${appManifest.html?.keywords ?? ''}" />
|
|
413
|
+
</head>
|
|
414
|
+
<body>
|
|
415
|
+
<div id="root"></div>
|
|
416
|
+
<script type="module" src="/index.jsx"></script>
|
|
417
|
+
</body>
|
|
513
418
|
</html>`;
|
|
514
419
|
return indexHtml;
|
|
515
420
|
}
|
|
@@ -527,7 +432,9 @@ export default defineConfig({
|
|
|
527
432
|
"type": currentPkg.type ?? "commonjs",
|
|
528
433
|
"scripts": {
|
|
529
434
|
"dev": "vite",
|
|
530
|
-
|
|
435
|
+
// No tsc here: the copy holds the whole workspace, and its server files import
|
|
436
|
+
// packages a browser build must not need. Typechecking is the job of 'cn validate'.
|
|
437
|
+
"build": "vite build",
|
|
531
438
|
"preview": "vite preview"
|
|
532
439
|
},
|
|
533
440
|
"dependencies": currentPkg.dependencies ?? {},
|
|
@@ -540,7 +447,8 @@ export default defineConfig({
|
|
|
540
447
|
}
|
|
541
448
|
}
|
|
542
449
|
if (pgkJson.devDependencies['vite'] === undefined) {
|
|
543
|
-
|
|
450
|
+
// Vite 8: what @vitejs/plugin-react 6 declares as peer
|
|
451
|
+
pgkJson.devDependencies['vite'] = "^8.0.0";
|
|
544
452
|
}
|
|
545
453
|
else {
|
|
546
454
|
ConsoleUtils_1.default.checkWarning(`Warning: Using custom Vite version: ${pgkJson.devDependencies['vite']}`);
|
|
@@ -553,57 +461,154 @@ export default defineConfig({
|
|
|
553
461
|
}
|
|
554
462
|
return pgkJson;
|
|
555
463
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
464
|
+
/**
|
|
465
|
+
* Starts the Vite dev server of one app, with hot reload on the real sources of the project.
|
|
466
|
+
* Behind the command: cn react dev <app>
|
|
467
|
+
*
|
|
468
|
+
* Unlike {@link BuildUtils.buildReactApp}, nothing of the project is copied: the staging
|
|
469
|
+
* folder `.codenotch/<appName>-dev` only holds the generated files (package.json, index.html,
|
|
470
|
+
* index.jsx, vite.config.mjs), and the config aliases the app component to its real path in
|
|
471
|
+
* the workspace. Editing a project file is therefore picked up live by Vite.
|
|
472
|
+
*
|
|
473
|
+
* The `/api/env` endpoint the app reads at startup is served by the dev server itself,
|
|
474
|
+
* through a small plugin of the generated config: the page behaves like the served bundle.
|
|
475
|
+
*
|
|
476
|
+
* Dependencies are installed in the staging on the first run only; delete the folder
|
|
477
|
+
* (or run 'cn react clean <app>') to force a fresh install.
|
|
478
|
+
*
|
|
479
|
+
* Blocks until the server is stopped (Ctrl+C), and returns the exit code it left.
|
|
480
|
+
*/
|
|
481
|
+
static async devReactApp(appFilePath, options) {
|
|
482
|
+
// resolve() already turns a relative path into an absolute one, based on the current directory
|
|
483
|
+
appFilePath = StringUtils_1.default.normalizePath((0, path_1.resolve)(appFilePath));
|
|
484
|
+
if ((0, fs_1.existsSync)(appFilePath) === false) {
|
|
485
|
+
console.log(chalk_1.default.red(`Error: File "${appFilePath}" not found`));
|
|
486
|
+
return 1;
|
|
487
|
+
}
|
|
488
|
+
let workspacePath = this.findWorkspaceFromFile(appFilePath) ?? '';
|
|
489
|
+
if (workspacePath === '' || (0, fs_1.existsSync)(workspacePath) === false) {
|
|
490
|
+
console.log(chalk_1.default.red(`Error: Could not find workspace manifest for file "${appFilePath}".`));
|
|
491
|
+
return 1;
|
|
492
|
+
}
|
|
493
|
+
// App manifest, named like the component
|
|
494
|
+
let appFilename = StringUtils_1.default.getFilenameFromUri(appFilePath);
|
|
495
|
+
let appManifestPath = StringUtils_1.default.normalizePath(`${StringUtils_1.default.getFolder(appFilePath)}/${appFilename.replace(/\.[^/.]+$/, '.manifest.json')}`);
|
|
496
|
+
if ((0, fs_1.existsSync)(appManifestPath) === false) {
|
|
497
|
+
console.log(chalk_1.default.red(`Error: App manifest file not found at "${appManifestPath}"`));
|
|
498
|
+
return 1;
|
|
499
|
+
}
|
|
500
|
+
let appManifest = JSON.parse(fs_2.default.readFileSync(appManifestPath, 'utf-8'));
|
|
501
|
+
let appName = `${appManifest.app?.name ?? ''}`.trim();
|
|
502
|
+
if (appName === '') {
|
|
503
|
+
console.log(chalk_1.default.red(`Error: App name not found in manifest at "${appManifestPath}"`));
|
|
504
|
+
return 1;
|
|
505
|
+
}
|
|
506
|
+
// Same environment as the one a built bundle reads, served by the dev server itself
|
|
507
|
+
let workspace = { manifest: this.getFullManifestAt(workspacePath), path: workspacePath };
|
|
508
|
+
let envVariables = await this.getCodenotchEnvVariables(workspace, {
|
|
509
|
+
appName: appName,
|
|
510
|
+
app: appManifest,
|
|
511
|
+
clusterUrl: options.clusterUrl
|
|
512
|
+
});
|
|
513
|
+
// Only generated files live in the staging: the sources stay, and are watched, in the workspace
|
|
514
|
+
let devDir = StringUtils_1.default.normalizePath(`${workspacePath}/.codenotch/${appName}-dev`);
|
|
515
|
+
console.log("Creating dev files...");
|
|
516
|
+
FileUtils_1.default.writeFileSync(devDir + '/package.json', JSON.stringify(this.createPkgJson(workspacePath, appName), null, 4));
|
|
517
|
+
FileUtils_1.default.writeFileSync(devDir + '/index.html', this.createIndexHtml(appManifest, appName));
|
|
518
|
+
FileUtils_1.default.writeFileSync(devDir + '/index.jsx', this.createIndexJsxDev());
|
|
519
|
+
FileUtils_1.default.writeFileSync(devDir + '/vite.config.mjs', this.createViteDevConfig(workspacePath, devDir, appFilePath, envVariables, options.port));
|
|
520
|
+
ConsoleUtils_1.default.check(`Dev files created in ${devDir}\n`);
|
|
521
|
+
// Vite 8 needs Node 20+: warn up front, its own error would be cryptic
|
|
522
|
+
const nodeMajor = parseInt(process.versions.node.split('.')[0], 10);
|
|
523
|
+
if (nodeMajor < 20) {
|
|
524
|
+
ConsoleUtils_1.default.checkWarning(`Node ${process.versions.node} detected, the dev server needs Node 20 or newer and may fail.`);
|
|
525
|
+
}
|
|
526
|
+
if ((0, fs_1.existsSync)(StringUtils_1.default.normalizePath(`${devDir}/node_modules`)) === false) {
|
|
527
|
+
console.log("Installing dependencies...");
|
|
528
|
+
const installCode = await ShellUtils_1.default.run(devDir, 'npm install --no-audit --no-fund');
|
|
529
|
+
if (installCode !== 0) {
|
|
530
|
+
console.log(chalk_1.default.red(`Error: npm install failed (exit code ${installCode}).`));
|
|
531
|
+
return installCode;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
console.log(chalk_1.default.green(`Starting dev server for "${appName}" (hot reload on ${workspacePath})...`));
|
|
535
|
+
// Vite runs FROM the workspace: tailwind 4 scans its sources from the working directory,
|
|
536
|
+
// and the staging holds none of them. The config still points everything at the staging.
|
|
537
|
+
const devDirPosix = devDir.replaceAll('\\', '/');
|
|
538
|
+
const viteCommand = `node "${devDirPosix}/node_modules/vite/bin/vite.js" --config "${devDirPosix}/vite.config.mjs"`;
|
|
539
|
+
return await ShellUtils_1.default.run(workspacePath, viteCommand);
|
|
540
|
+
}
|
|
541
|
+
/** The dev entry: same contract as the built one, the app itself comes through the '@app' alias */
|
|
542
|
+
static createIndexJsxDev() {
|
|
543
|
+
return `
|
|
544
|
+
import { createRoot } from 'react-dom/client';
|
|
545
|
+
import App from '@app';
|
|
546
|
+
import { init } from '@codenotch/codenotch.react';
|
|
547
|
+
|
|
548
|
+
// The environment is exposed by the dev server (see the codenotch-env plugin of vite.config.mjs)
|
|
549
|
+
const root = createRoot(document.getElementById('root'));
|
|
550
|
+
fetch('/api/env')
|
|
551
|
+
\t.then(response => response.json())
|
|
552
|
+
\t.then(data => {
|
|
553
|
+
\t\tinit(data);
|
|
554
|
+
\t\troot.render(<App />);
|
|
555
|
+
\t})
|
|
556
|
+
\t.catch(error => {
|
|
557
|
+
\t\tconsole.error('Error fetching environment variables:', error);
|
|
558
|
+
\t\tinit({});
|
|
559
|
+
\t\troot.render(<App />);
|
|
560
|
+
\t});
|
|
561
|
+
`.trim();
|
|
562
|
+
}
|
|
563
|
+
/**
|
|
564
|
+
* The dev flavoured Vite config: the app is aliased to its real file in the workspace so that
|
|
565
|
+
* hot reload watches the project sources, and a tiny plugin serves the Codenotch environment.
|
|
566
|
+
*/
|
|
567
|
+
static createViteDevConfig(workspacePath, devDir, appFilePath, envVariables, port) {
|
|
568
|
+
const workspacePosix = workspacePath.replaceAll('\\', '/');
|
|
569
|
+
const devDirPosix = devDir.replaceAll('\\', '/');
|
|
570
|
+
const appFilePosix = appFilePath.replaceAll('\\', '/');
|
|
571
|
+
return `
|
|
572
|
+
import { defineConfig } from 'vite'
|
|
573
|
+
import react from '@vitejs/plugin-react'
|
|
574
|
+
|
|
575
|
+
// The same environment a built bundle reads from its .env, served here by the dev server
|
|
576
|
+
const codenotchEnv = ${JSON.stringify(envVariables, null, 4)};
|
|
577
|
+
|
|
578
|
+
export default defineConfig({
|
|
579
|
+
// The server is rooted here (index.html, node_modules), but runs from the workspace
|
|
580
|
+
root: ${JSON.stringify(devDirPosix)},
|
|
581
|
+
plugins: [
|
|
582
|
+
react(),
|
|
583
|
+
{
|
|
584
|
+
name: 'codenotch-env',
|
|
585
|
+
configureServer(server) {
|
|
586
|
+
server.middlewares.use('/api/env', (req, res) => {
|
|
587
|
+
res.setHeader('Content-Type', 'application/json');
|
|
588
|
+
res.end(JSON.stringify(codenotchEnv));
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
},
|
|
592
|
+
],
|
|
593
|
+
resolve: {
|
|
594
|
+
alias: [
|
|
595
|
+
// The app is NOT copied here: it is loaded, and watched, from the workspace
|
|
596
|
+
{ find: '@app', replacement: ${JSON.stringify(appFilePosix)} },
|
|
597
|
+
],
|
|
598
|
+
},
|
|
599
|
+
server: {
|
|
600
|
+
port: ${port},
|
|
601
|
+
strictPort: true,
|
|
602
|
+
fs: {
|
|
603
|
+
// The sources live outside the vite root, in the workspace
|
|
604
|
+
allow: [${JSON.stringify(workspacePosix)}],
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
})`.trim();
|
|
580
608
|
}
|
|
581
609
|
static getFullManifestAt(folderPath) {
|
|
582
610
|
let manifest = this.getManifestAt(folderPath);
|
|
583
|
-
|
|
584
|
-
let result = {
|
|
585
|
-
projectName: manifest.projectName,
|
|
586
|
-
serviceName: manifest.serviceName,
|
|
587
|
-
version: manifest.version,
|
|
588
|
-
index: manifest.index,
|
|
589
|
-
dependencies: manifest.dependencies,
|
|
590
|
-
reactApplications: manifestCache.reactApplications,
|
|
591
|
-
packages: manifest.packages,
|
|
592
|
-
languages: manifest.languages,
|
|
593
|
-
roles: manifest.roles,
|
|
594
|
-
postInstallationProcesses: manifest.postInstallationProcesses,
|
|
595
|
-
apis: manifestCache.apis,
|
|
596
|
-
applications: manifestCache.applications,
|
|
597
|
-
emails: manifestCache.emails,
|
|
598
|
-
documentDataSources: manifestCache.documentDataSources,
|
|
599
|
-
expressComponents: manifestCache.expressComponents,
|
|
600
|
-
htmls: manifestCache.htmls,
|
|
601
|
-
pdfs: manifestCache.pdfs,
|
|
602
|
-
processes: manifestCache.processes,
|
|
603
|
-
scripts: manifestCache.scripts,
|
|
604
|
-
tableDataSources: manifestCache.tableDataSources,
|
|
605
|
-
};
|
|
606
|
-
return result;
|
|
611
|
+
return manifest;
|
|
607
612
|
}
|
|
608
613
|
static getManifestAt(folderPath) {
|
|
609
614
|
let filePath = StringUtils_1.default.normalizePath(`${folderPath}/manifest.json`);
|
|
@@ -613,49 +618,6 @@ export default defineConfig({
|
|
|
613
618
|
let json = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
614
619
|
return JSON.parse(json);
|
|
615
620
|
}
|
|
616
|
-
static getManifestCacheAt(folderPath) {
|
|
617
|
-
let filePath = StringUtils_1.default.normalizePath(`${folderPath}/manifest.cache.json`);
|
|
618
|
-
if ((0, fs_1.existsSync)(filePath) === false) {
|
|
619
|
-
throw new Error(`Manifest cache file not found at path "${filePath}"`);
|
|
620
|
-
}
|
|
621
|
-
let json = (0, fs_1.readFileSync)(filePath, 'utf-8');
|
|
622
|
-
return JSON.parse(json);
|
|
623
|
-
}
|
|
624
|
-
static getAumlVariables(workpace, tenantName, clusterUrl) {
|
|
625
|
-
let workspaceManifest = workpace?.manifest;
|
|
626
|
-
let result = {
|
|
627
|
-
serviceName: workspaceManifest?.serviceName ?? 'DEV',
|
|
628
|
-
tenant: {
|
|
629
|
-
displayName: tenantName,
|
|
630
|
-
name: tenantName,
|
|
631
|
-
clusterUrl: clusterUrl
|
|
632
|
-
},
|
|
633
|
-
languages: workspaceManifest?.languages ?? ['en'],
|
|
634
|
-
appManifest: workpace.manifest,
|
|
635
|
-
packageVersions: workspaceManifest?.packages ?? {}
|
|
636
|
-
};
|
|
637
|
-
return result;
|
|
638
|
-
}
|
|
639
|
-
static async getGlobalAumlVariableDefinitions(workpace, tenantName, clusterUrl) {
|
|
640
|
-
let workspaceManifest = workpace?.manifest;
|
|
641
|
-
return `window.serviceName = "${workspaceManifest?.serviceName ?? 'DEV'}";
|
|
642
|
-
window.tenant = ${JSON.stringify({
|
|
643
|
-
displayName: tenantName,
|
|
644
|
-
name: tenantName,
|
|
645
|
-
clusterUrl: clusterUrl
|
|
646
|
-
}, null, 4)};
|
|
647
|
-
window.languages = ${JSON.stringify(workspaceManifest?.languages ?? ['en'], null, 4)};
|
|
648
|
-
window.user = ${JSON.stringify({
|
|
649
|
-
id: '',
|
|
650
|
-
roles: [],
|
|
651
|
-
groups: [],
|
|
652
|
-
email: '',
|
|
653
|
-
firstName: '',
|
|
654
|
-
lastName: ''
|
|
655
|
-
}, null, 4)};
|
|
656
|
-
window.appManifest = ${JSON.stringify(workpace.manifest, null, 4)};
|
|
657
|
-
window.packageVersions = ${JSON.stringify(workpace.manifest.packages ?? {}, null, 4)}`;
|
|
658
|
-
}
|
|
659
621
|
}
|
|
660
622
|
exports.default = BuildUtils;
|
|
661
623
|
//# sourceMappingURL=BuildUtils.js.map
|