@imtf/profile-scripts 2.0.0-beta.0 → 2.0.0

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 ADDED
@@ -0,0 +1,275 @@
1
+ # @imtf/profile-scripts (Vite + Module Federation)
2
+
3
+ ## Overview
4
+
5
+ `profile-scripts` is a standardized build and development utility designed for Profile applications within the ICOS.
6
+
7
+ It provides a **vite-based build** with optional **Module Federation integration**.
8
+
9
+ ---
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install --save-dev @imtf/profile-scripts
15
+ ```
16
+
17
+ or
18
+
19
+ ```bash
20
+ yarn add -D @imtf/profile-scripts
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Usage
26
+
27
+ ### Start (development/watch mode)
28
+
29
+ ```bash
30
+ profile-scripts start
31
+ ```
32
+
33
+ Starts the build in watch mode and serves output at:
34
+
35
+ ```
36
+ http://localhost:3010
37
+ ```
38
+
39
+ ---
40
+
41
+ ### Build (Production)
42
+
43
+ ```bash
44
+ profile-scripts build
45
+ ```
46
+
47
+ Generates the production bundle in the `build/` directory.
48
+
49
+ ---
50
+
51
+ ## CLI Options
52
+
53
+ ### `--entryPoint`
54
+
55
+ Specify a custom entry file.
56
+
57
+ ```bash
58
+ profile-scripts start --entryPoint src/index.ts
59
+ ```
60
+
61
+ If not provided, the following files are checked (in order):
62
+
63
+ ```
64
+ index.ts
65
+ index.tsx
66
+ index.js
67
+ index.jsx
68
+ src/index.ts
69
+ src/index.tsx
70
+ src/index.js
71
+ src/index.jsx
72
+ ```
73
+
74
+ ---
75
+
76
+ ### `--federation`
77
+
78
+ Enable Module Federation support.
79
+
80
+ ```bash
81
+ profile-scripts start --federation
82
+ ```
83
+
84
+ When enabled:
85
+ - Loads configuration from `federation.config.js` or `federation.config.mjs` in project root
86
+ - Integrates with `vite-plugin-federation`
87
+
88
+ ---
89
+
90
+ ### `--externalGlobal`
91
+
92
+ Map external dependencies to global variables (optional).
93
+
94
+ ```bash
95
+ profile-scripts build --externalGlobal=react/jsx-runtime=window.jsxRuntime
96
+ ```
97
+
98
+ Use this when a dependency is provided globally by the host application and should not be bundled.
99
+
100
+ ---
101
+
102
+ ## Project Requirements
103
+
104
+ Minimal structure:
105
+
106
+ ```
107
+ project-root/
108
+ src/
109
+ index.tsx (or equivalent entry)
110
+ package.json
111
+ ```
112
+
113
+ For Module Federation:
114
+
115
+ ```
116
+ federation.config.js
117
+ ```
118
+
119
+ ---
120
+
121
+ ## Remote Application Requirements
122
+
123
+ To enable Module Federation integration, the **remote application** must be configured as follows.
124
+
125
+ ### Module Federation Configuration
126
+
127
+ ```js
128
+ module.exports = {
129
+ name: "remote-app",
130
+ exposes: {
131
+ "./App": "./src/App",
132
+ },
133
+ filename: "remoteEntry.js",
134
+ library: { type: "module" }, // **required**
135
+ };
136
+ ```
137
+
138
+ ---
139
+
140
+ ### Build Configuration
141
+
142
+ ```js
143
+ experiments: { outputModule: true },
144
+
145
+ externalsType: "global",
146
+
147
+ externals: {
148
+ react: "React",
149
+ "react-dom": "ReactDOM",
150
+ };
151
+ ```
152
+
153
+ ### Notes
154
+
155
+ * The `library.type = "module"` configuration is **mandatory** for compatibility with vite-based host applications
156
+ * `outputModule: true` ensures the remote is emitted as an ES module
157
+ * React dependencies must be externalised and provided by the host application
158
+
159
+ ---
160
+
161
+ ## SVG Handling
162
+
163
+ Built-in SVG support:
164
+
165
+ - Files inside `src/` → transformed into React components
166
+ - Files inside `src/assets/` or outside `src/` → converted to base64 data URLs
167
+
168
+ ---
169
+
170
+ ## CSS Handling
171
+
172
+ CSS is automatically injected into the JavaScript bundle.
173
+ No separate CSS files are generated.
174
+
175
+ ---
176
+
177
+ ## Output
178
+
179
+ Build output:
180
+
181
+ ```
182
+ build/
183
+ index.js
184
+ ```
185
+
186
+ - Format: IIFE
187
+ - Designed for integration into host applications
188
+
189
+ ---
190
+
191
+ ## Environment Variable
192
+
193
+ ### `IMTF_MINIFY_WEBAPP`
194
+
195
+ Controls minification:
196
+
197
+ ```bash
198
+ IMTF_MINIFY_WEBAPP=false profile-scripts build
199
+ ```
200
+
201
+ - Default: minification enabled
202
+ - Uses Vite default minifier
203
+
204
+ ---
205
+
206
+ ## Notes
207
+
208
+ - vite is the default build system
209
+ - Module Federation is enabled only via `--federation`
210
+ - Entry point is optional but must resolve to a valid file
211
+ - External globals should be used only when dependencies are provided by the host
212
+
213
+ ---
214
+ ## Profile Configuration
215
+ Two supported approaches are available based on how the remote is resolved.
216
+
217
+ ---
218
+
219
+ ### Option 1: URL-based Remote (Static)
220
+
221
+ ```js
222
+ export default {
223
+ name: "host-app",
224
+ remotes: {
225
+ remoteModule: {
226
+ externalType: "url",
227
+ external: "http://localhost:3021/remoteEntry.js",
228
+ from: "webpack",
229
+ format: "esm",
230
+ },
231
+ },
232
+ };
233
+ ```
234
+
235
+ ---
236
+
237
+ ### Option 2: Promise-based Remote (Dynamic)
238
+
239
+ Use this when the remote URL needs to be resolved dynamically at runtime.
240
+
241
+ ```js
242
+ export default {
243
+ name: "host-app",
244
+ remotes: {
245
+ remoteapp: {
246
+ externalType: "promise",
247
+ external: "<<resolver function as string>>",
248
+ from: "webpack",
249
+ format: "esm",
250
+ },
251
+ },
252
+ };
253
+ ```
254
+
255
+ ---
256
+
257
+ ## Troubleshooting
258
+
259
+ ### Entry point not found
260
+
261
+ Ensure one of the supported entry files exists or pass `--entryPoint`.
262
+
263
+ ---
264
+
265
+ ### Federation configuration missing
266
+
267
+ Ensure `federation.config.js` or `.mjs` exists when using `--federation`.
268
+
269
+ ---
270
+
271
+ ### Runtime dependency issues
272
+
273
+ If a dependency is expected from the host, configure it using `--externalGlobal`.
274
+
275
+ ---
@@ -7,26 +7,13 @@ const args = process.argv.slice(2);
7
7
  const scriptIndex = args.findIndex((x) => x === "build" || x === "start");
8
8
  const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
9
9
 
10
- const useVite = args.includes("--vite");
11
- const useViteFederation = args.includes("--federation");
12
-
13
- // federation automatically implies vite
14
- const useViteBuild = useVite || useViteFederation;
15
-
16
- // Remove internal routing flags before forwarding
17
- const cleanedArgs = args.filter(
18
- (arg) => arg !== "--vite"
19
- );
20
-
21
- const scriptPath = useViteBuild
22
- ? require.resolve("../scripts/viteBuild.mjs")
23
- : require.resolve("../scripts/esbuild.mjs");
10
+ const scriptPath = require.resolve("../scripts/viteBuild.mjs");
24
11
 
25
12
  switch (script) {
26
13
  case "start":
27
14
  case "build": {
28
- const nodeArgs = scriptIndex > 0 ? cleanedArgs.slice(0, scriptIndex) : [];
29
- const scriptArgs = cleanedArgs.slice(scriptIndex + 1);
15
+ const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];
16
+ const scriptArgs = args.slice(scriptIndex + 1);
30
17
 
31
18
  if (script === "start") {
32
19
  scriptArgs.push("--watch");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imtf/profile-scripts",
3
- "version": "2.0.0-beta.0",
3
+ "version": "2.0.0",
4
4
  "description": "Default scripts to bundle & transpile imtf front-end plugins",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -12,28 +12,20 @@
12
12
  "changelog.md"
13
13
  ],
14
14
  "scripts": {
15
- "build": "NODE_ENV=production node scripts/esbuild.mjs --entryPoint=src/index.tsx",
16
- "start": "node scripts/esbuild.mjs --entryPoint=src/index.tsx --watch"
15
+ "build": "NODE_ENV=production node scripts/viteBuild.mjs",
16
+ "start": "node scripts/viteBuild.mjs --watch"
17
17
  },
18
18
  "prettier": "@imtf/prettier-config",
19
19
  "license": "UNLICENSED",
20
20
  "private": false,
21
21
  "dependencies": {
22
22
  "@originjs/vite-plugin-federation": "^1.4.1",
23
- "@svgr/core": "^8.1.0",
24
- "@svgr/plugin-jsx": "^8.1.0",
25
- "@svgr/plugin-svgo": "^8.1.0",
26
- "@vitejs/plugin-react": "^5.1.4",
27
- "esbuild": "^0.27.0",
28
- "esbuild-css-modules-plugin": "^3.1.4",
29
- "esbuild-plugin-external-global": "^1.0.1",
30
- "esbuild-plugin-inline-css": "^0.0.1",
31
- "http-server": "^14.1.1",
23
+ "@vitejs/plugin-react": "^6.0.4",
24
+ "esbuild": "^0.28.1",
32
25
  "minimist": "^1.2.8",
33
- "serve-handler": "^6.1.6",
34
- "vite": "^7.3.1",
35
- "vite-plugin-css-injected-by-js": "^4.0.1",
36
- "vite-tsconfig-paths": "^6.1.1"
26
+ "serve-handler": "^6.1.7",
27
+ "vite": "^8.1.5",
28
+ "vite-plugin-css-injected-by-js": "^5.0.2"
37
29
  },
38
30
  "devDependencies": {
39
31
  "@types/minimist": "^1.2.5"
@@ -0,0 +1,50 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+
4
+ const DEFAULT_ENTRYPOINTS = [
5
+ "src/index.ts",
6
+ "src/index.tsx",
7
+ "src/index.js",
8
+ "src/index.jsx",
9
+ "index.ts",
10
+ "index.tsx",
11
+ "index.js",
12
+ "index.jsx",
13
+ ];
14
+
15
+ /**
16
+ * Resolves the application entry point.
17
+ * Uses the provided entryPoint, otherwise falls back to defaults.
18
+ * Throws a simple error if no valid entry file is found.
19
+ *
20
+ * @param {string} [entryPoint] - Entry point passed via CLI
21
+ * @returns {string} Absolute path to resolved entry file
22
+ */
23
+ const resolveEntryPoint = (entryPoint) => {
24
+ const consumerRoot = process.cwd();
25
+
26
+ // Use CLI entryPoint if provided
27
+ if (entryPoint) {
28
+ const resolvedPath = path.isAbsolute(entryPoint)
29
+ ? entryPoint
30
+ : path.resolve(consumerRoot, entryPoint);
31
+
32
+ if (!fs.existsSync(resolvedPath)) {
33
+ throw new Error(`[profile-scripts] entryPoint not found: ${entryPoint}`);
34
+ }
35
+
36
+ return resolvedPath;
37
+ }
38
+
39
+ // Resolve from defaults
40
+ for (const candidate of DEFAULT_ENTRYPOINTS) {
41
+ const fullPath = path.resolve(consumerRoot, candidate);
42
+ if (fs.existsSync(fullPath)) {
43
+ return fullPath;
44
+ }
45
+ }
46
+
47
+ throw new Error(`[profile-scripts] entryPoint not found`);
48
+ };
49
+
50
+ export default resolveEntryPoint;
@@ -1,9 +1,3 @@
1
- /* eslint-disable @typescript-eslint/no-unsafe-return */
2
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
3
- /* eslint-disable @typescript-eslint/no-unsafe-argument */
4
- /* eslint-disable @typescript-eslint/no-unsafe-assignment */
5
- /* eslint-disable @typescript-eslint/no-unsafe-call */
6
-
7
1
  import http from "http";
8
2
  import fs from "node:fs";
9
3
  import path from "path";
@@ -14,10 +8,10 @@ import react from "@vitejs/plugin-react";
14
8
  import { transform } from "esbuild";
15
9
  import minimist from "minimist";
16
10
  import handler from "serve-handler";
17
- import { build as viteBuild } from "vite";
11
+ import { build as viteBuild, esmExternalRequirePlugin } from "vite";
18
12
  import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";
19
- import tsconfigPaths from "vite-tsconfig-paths";
20
13
 
14
+ import resolveEntryPoint from "./utils/resolveEntryPoint.mjs";
21
15
  import notifierPlugin from "./vitePlugins/viteNotifierPlugin.mjs";
22
16
  import svgPlugin from "./vitePlugins/viteSvgPlugin.mjs";
23
17
 
@@ -26,20 +20,20 @@ const {
26
20
  entryPoint,
27
21
  externalGlobal,
28
22
  federation: enableFederation,
29
- } = minimist(process.argv.slice(2));
23
+ } = /** @type {{ watch?: boolean; entryPoint?: string; externalGlobal?: string | string[]; federation?: boolean }} */ (
24
+ minimist(process.argv.slice(2))
25
+ );
30
26
 
31
27
  const consumerRoot = process.cwd();
32
28
  const outDir = "build";
33
29
 
34
- const entryAbs = entryPoint
35
- ? path.resolve(consumerRoot, entryPoint)
36
- : path.resolve(consumerRoot, "src/index.js");
30
+ const entryAbs = resolveEntryPoint(entryPoint);
37
31
 
38
32
  // Force JSX transform for .js files in src
39
33
  const jsxPreTransformPlugin = {
40
34
  name: "jsx-pre-transform",
41
35
  enforce: "pre",
42
- async transform(code, id) {
36
+ async transform(/** @type {string} */ code, /** @type {string} */ id) {
43
37
  if (id.endsWith(".js") && id.includes(path.resolve(consumerRoot, "src"))) {
44
38
  const result = await transform(code, {
45
39
  loader: "jsx",
@@ -61,7 +55,7 @@ const jsxPreTransformPlugin = {
61
55
  const packageJsonResolver = {
62
56
  name: "package-json-resolver",
63
57
  enforce: "pre",
64
- resolveId(source) {
58
+ resolveId(/** @type {string} */ source) {
65
59
  if (!source.endsWith("/package.json")) return null;
66
60
 
67
61
  const pkgName = source.replace(/\/package\.json$/, "");
@@ -90,8 +84,8 @@ const externalGlobals = externalGlobal
90
84
  const [key, value] = curr.split("=");
91
85
  acc[key] = value;
92
86
  return acc;
93
- }, {})
94
- : {};
87
+ }, /** @type {Record<string, string>} */ ({}))
88
+ : /** @type {Record<string, string>} */ ({});
95
89
 
96
90
  // Dynamically resolve optional federation.config.(js|mjs) from consumer root
97
91
  const resolveFederationConfig = async () => {
@@ -102,7 +96,10 @@ const resolveFederationConfig = async () => {
102
96
  for (const file of candidates) {
103
97
  const fullPath = path.resolve(consumerRoot, file);
104
98
  if (fs.existsSync(fullPath)) {
105
- const mod = await import(pathToFileURL(fullPath).href);
99
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
100
+ const mod = /** @type {Record<string, unknown>} */ (
101
+ await import(pathToFileURL(fullPath).href)
102
+ );
106
103
  return mod.default ?? mod;
107
104
  }
108
105
  }
@@ -127,9 +124,6 @@ const vitePlugins = [
127
124
  include: /\.(js|jsx|ts|tsx)$/,
128
125
  }),
129
126
 
130
- // Resolve tsconfig path aliases
131
- tsconfigPaths(),
132
-
133
127
  // Inject CSS into the bundle for library consumers without needing separate CSS files
134
128
  cssInjectedByJsPlugin(),
135
129
 
@@ -143,8 +137,18 @@ const vitePlugins = [
143
137
  // Inject Module Federation support when --federation flag is provided
144
138
  if (enableFederation) {
145
139
  const federationConfig = await resolveFederationConfig();
146
-
147
140
  vitePlugins.push(federation(federationConfig));
141
+ // Vite 8 (rolldown) disables codeSplitting for iife format, making manualChunks invalid.
142
+ // Since this is a consumer-only federation setup, manualChunks is not needed.
143
+ vitePlugins.push({
144
+ name: "remove-manual-chunks-for-iife",
145
+ enforce: "post",
146
+ outputOptions(opts) {
147
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
148
+ delete opts.manualChunks;
149
+ return opts;
150
+ },
151
+ });
148
152
  }
149
153
 
150
154
  /**
@@ -154,25 +158,34 @@ if (enableFederation) {
154
158
  const viteConfig = {
155
159
  root: consumerRoot,
156
160
  plugins: vitePlugins,
157
- logLevel: watch ? "error" : "info", // !!! Need to discuss
161
+ logLevel: watch ? "error" : "info",
158
162
  build: {
159
163
  outDir,
160
164
  emptyOutDir: true,
161
165
  target: "esnext",
162
166
  sourcemap: watch,
167
+ chunkSizeWarningLimit: 3000,
163
168
  rollupOptions: {
164
169
  input: entryAbs,
165
- external: [
166
- "react",
167
- "react-dom",
168
- "react-router-dom",
169
- "IMTFPlugins",
170
- ...Object.keys(externalGlobals),
170
+ // Fixes Vite 8+ (rolldown) leaving a literal require("react") for nested CJS deps
171
+ // in 'iife' output (rolldown/rolldown#8349). Don't also list these in a top-level
172
+ // 'external' option - that silently disables this plugin's require() rewrite for
173
+ // the duplicated entries.
174
+ plugins: [
175
+ esmExternalRequirePlugin({
176
+ external: [
177
+ "react",
178
+ "react-dom",
179
+ "react-router-dom",
180
+ "IMTFPlugins",
181
+ ...Object.keys(externalGlobals),
182
+ ],
183
+ }),
171
184
  ],
172
185
  output: {
173
186
  entryFileNames: "index.js",
174
187
  format: "iife",
175
- inlineDynamicImports: false,
188
+ // inlineDynamicImports: false,
176
189
  globals: {
177
190
  react: "React",
178
191
  "react-dom": "ReactDOM",
@@ -185,6 +198,9 @@ const viteConfig = {
185
198
  minify: watch ? false : process.env.IMTF_MINIFY_WEBAPP !== "false",
186
199
  watch: watch ? {} : null,
187
200
  },
201
+ define: {
202
+ "import.meta": "{}",
203
+ },
188
204
  };
189
205
 
190
206
  // Run Vite build in either watch or build mode
@@ -192,6 +208,7 @@ if (watch) {
192
208
  await viteBuild(viteConfig);
193
209
 
194
210
  http
211
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return
195
212
  .createServer((...params) => handler(...params, { public: outDir }))
196
213
  .listen(3010, () => {
197
214
  // eslint-disable-next-line no-console
@@ -1,25 +1,35 @@
1
+ /* eslint-disable no-console */
2
+
3
+ /**
4
+ * Logs Vite build and rebuild status with rebuild count.
5
+ * Distinguishes initial build vs subsequent rebuilds in watch mode.
6
+ *
7
+ * @param {boolean} watch - Whether running in watch mode
8
+ * @returns {import('vite').Plugin}
9
+ */
1
10
  const viteNotifierPlugin = (watch) => {
2
- let count = 0;
11
+ let isFirstBuild = true;
12
+ let rebuildCount = 0;
3
13
 
4
14
  return {
5
15
  name: "notifier-plugin-vite",
6
16
 
7
- buildStart() {
8
- count = 0;
9
- },
10
-
11
17
  buildEnd(error) {
12
18
  if (error) return;
13
19
 
14
- if (count++ === 0) {
15
- if (watch) {
16
- console.log(`1st build: ${Date.now()}`);
17
- } else {
18
- console.log("Successfully built");
19
- }
20
- } else {
21
- console.log(`Rebuilt: ${Date.now()}`);
20
+ if (!watch) {
21
+ console.log("Successfully built");
22
+ return;
22
23
  }
24
+
25
+ if (isFirstBuild) {
26
+ console.log(`1st build: ${Date.now()}`);
27
+ isFirstBuild = false;
28
+ return;
29
+ }
30
+
31
+ rebuildCount += 1;
32
+ console.log(`Rebuilt (${rebuildCount}): ${Date.now()}`);
23
33
  },
24
34
  };
25
35
  };
@@ -1,3 +1,17 @@
1
+ import fs from "node:fs";
2
+ import path from "path";
3
+
4
+ import { transform } from "@svgr/core";
5
+
6
+ /**
7
+ * Vite plugin to transform SVG imports based on project conventions.
8
+ *
9
+ * - SVGs outside `src/` or inside `src/assets/` are converted to base64 data URLs
10
+ * - SVGs inside `src/` are transformed into React components using SVGR
11
+ *
12
+ * @param {Record<string, unknown>} [options] - SVGR configuration options
13
+ * @returns {import('vite').Plugin}
14
+ */
1
15
  const viteSvgPlugin = (options = {}) => {
2
16
  return {
3
17
  name: "vite-svgr-plugin",
@@ -22,7 +36,7 @@ const viteSvgPlugin = (options = {}) => {
22
36
  const dataurl = `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`;
23
37
  return {
24
38
  code: `export default ${JSON.stringify(dataurl)};`,
25
- map: null
39
+ map: null,
26
40
  };
27
41
  }
28
42
 
@@ -31,17 +45,17 @@ const viteSvgPlugin = (options = {}) => {
31
45
  svg,
32
46
  {
33
47
  plugins: ["@svgr/plugin-svgo", "@svgr/plugin-jsx"],
34
- ...options
48
+ ...options,
35
49
  },
36
- { filePath: svgPath }
50
+ { filePath: svgPath },
37
51
  );
38
52
 
39
53
  return {
40
54
  code: contents,
41
- map: null
55
+ map: null,
42
56
  };
43
- }
57
+ },
44
58
  };
45
- }
59
+ };
46
60
 
47
61
  export default viteSvgPlugin;
@@ -1,94 +0,0 @@
1
- import { build, context } from "esbuild";
2
- import esbuild from "esbuild-plugin-external-global";
3
- import InlineCSSPlugin from "esbuild-plugin-inline-css";
4
- import CssModulesPlugin from "esbuild-css-modules-plugin";
5
- import minimist from "minimist";
6
- import HttpServer from "http-server";
7
-
8
- // eslint-disable-next-line import/no-named-as-default-member
9
- const externalGlobalPlugin = esbuild.externalGlobalPlugin;
10
-
11
- import notifierPlugin from "./notifierPlugin.mjs";
12
- import svgPlugin from "./svgPlugin.mjs";
13
-
14
- const {
15
- watch,
16
- entryPoint,
17
- externalGlobal,
18
- outbase = "src",
19
- } = minimist(process.argv.slice(2));
20
-
21
- const externalGlobals = externalGlobal
22
- ? (typeof externalGlobal === "string"
23
- ? [externalGlobal]
24
- : externalGlobal
25
- ).reduce((acc, curr) => {
26
- const [key, value] = curr.split("=");
27
- acc[key] = value;
28
- return acc;
29
- }, {})
30
- : {};
31
-
32
- const entryPoints = entryPoint
33
- ? typeof entryPoint === "string"
34
- ? [entryPoint]
35
- : entryPoint
36
- : ["src/index.js"];
37
-
38
- /**
39
- * @type {import('esbuild').BuildOptions}
40
- */
41
- const config = {
42
- entryPoints,
43
- outbase,
44
- outdir: "build",
45
- platform: "browser",
46
- bundle: true,
47
- target: "es2024",
48
- metafile: true,
49
-
50
- sourcemap: watch ? "linked" : "external",
51
-
52
- minify: watch === true ? false : process.env.IMTF_MINIFY_WEBAPP !== "false",
53
-
54
- loader: {
55
- // Enable JSX in .js files too
56
- ".js": "jsx",
57
- // Embed fonts
58
- ".eot": "dataurl",
59
- ".ttf": "dataurl",
60
- ".woff": "dataurl",
61
- ".woff2": "dataurl",
62
- // Embed images
63
- ".gif": "dataurl",
64
- ".jpg": "dataurl",
65
- ".png": "dataurl",
66
- },
67
-
68
- plugins: [
69
- CssModulesPlugin({ inject: true }),
70
- InlineCSSPlugin(),
71
- svgPlugin(),
72
- externalGlobalPlugin({
73
- react: "window.React",
74
- "react-dom": "window.ReactDOM",
75
- "react-router-dom": "window.reactRouterDom",
76
- IMTFPlugins: "window.IMTFPlugins",
77
- ...externalGlobals,
78
- }),
79
- notifierPlugin(watch),
80
- ],
81
- };
82
-
83
- if (watch) {
84
- const ctx = await context(config);
85
-
86
- // Enable watch mode
87
- await ctx.watch();
88
-
89
- // Create a server for the build directory
90
- const server = HttpServer.createServer({ root: "build" });
91
- server.listen(3010, () => console.log("Running at http://localhost:3010"));
92
- } else {
93
- await build(config);
94
- }
@@ -1,24 +0,0 @@
1
- const notifierPlugin = (watch) => ({
2
- name: "svgr",
3
- setup(build) {
4
- let count = 0;
5
-
6
- build.onEnd((result) => {
7
- if (result.errors.length > 0) {
8
- return;
9
- }
10
-
11
- if (count++ === 0) {
12
- if(watch) {
13
- console.log(`1st build: ${new Date().getTime()}`);
14
- } else {
15
- console.log(`Successfully built`);
16
- }
17
- } else {
18
- console.log(`Rebuilt: ${new Date().getTime()}`);
19
- }
20
- });
21
- },
22
- });
23
-
24
- export default notifierPlugin;
@@ -1,44 +0,0 @@
1
- import { transform } from "@svgr/core";
2
- import fs from "fs";
3
- import path from "path";
4
-
5
- const svgPlugin = (options = {}) => ({
6
- name: "svgr",
7
- setup(build) {
8
- build.onLoad({ filter: /\.svg$/ }, async (args) => {
9
- // Read file content
10
- const svg = await fs.promises.readFile(args.path, "utf8");
11
-
12
- // Determine relative path
13
- const relativePath = path.relative(process.cwd(), args.path);
14
-
15
- // This is an asset ==> dataurl
16
- if (
17
- !relativePath.startsWith("src/") ||
18
- relativePath.startsWith("src/assets/")
19
- ) {
20
- return {
21
- contents: svg,
22
- loader: "dataurl",
23
- };
24
- }
25
-
26
- // Otherwise it's a react component
27
- const contents = await transform(
28
- svg,
29
- {
30
- plugins: ["@svgr/plugin-svgo", "@svgr/plugin-jsx"],
31
- ...options,
32
- },
33
- { filePath: args.path }
34
- );
35
-
36
- return {
37
- contents,
38
- loader: "jsx",
39
- };
40
- });
41
- },
42
- });
43
-
44
- export default svgPlugin;