@angular-architects/native-federation-v4 21.1.4 → 21.1.7
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 +7 -7
- package/migration-collection.json +1 -1
- package/package.json +16 -8
- package/src/builders/build/builder.d.ts +2 -1
- package/src/builders/build/builder.d.ts.map +1 -1
- package/src/builders/build/builder.js +117 -113
- package/src/builders/build/schema.d.ts +1 -0
- package/src/builders/build/schema.json +3 -0
- package/src/builders/build/setup-builder-env-variables.d.ts +2 -0
- package/src/builders/build/setup-builder-env-variables.d.ts.map +1 -0
- package/src/builders/build/setup-builder-env-variables.js +9 -0
- package/src/plugin/externals-skip-list.js +1 -1
- package/src/utils/angular-bundler.d.ts +12 -0
- package/src/utils/angular-bundler.d.ts.map +1 -0
- package/src/utils/angular-bundler.js +167 -0
- package/src/utils/angular-esbuild-adapter.d.ts +5 -5
- package/src/utils/angular-esbuild-adapter.d.ts.map +1 -1
- package/src/utils/angular-esbuild-adapter.js +81 -261
- package/src/utils/node-modules-bundler.d.ts +12 -0
- package/src/utils/node-modules-bundler.d.ts.map +1 -0
- package/src/utils/node-modules-bundler.js +113 -0
- package/src/utils/create-compiler-options.d.ts +0 -5
- package/src/utils/create-compiler-options.d.ts.map +0 -1
- package/src/utils/create-compiler-options.js +0 -42
- package/src/utils/event-source.d.ts +0 -10
- package/src/utils/event-source.d.ts.map +0 -1
- package/src/utils/event-source.js +0 -10
- package/src/utils/mem-resuts.d.ts +0 -29
- package/src/utils/mem-resuts.d.ts.map +0 -1
- package/src/utils/mem-resuts.js +0 -50
- package/src/utils/rebuild-events.d.ts +0 -8
- package/src/utils/rebuild-events.d.ts.map +0 -1
- package/src/utils/rebuild-events.js +0 -4
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as fs from 'fs';
|
|
4
|
+
import { createRequire } from 'node:module';
|
|
5
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
6
|
+
import JSON5 from 'json5';
|
|
7
|
+
import { transformSupportedBrowsersToTargets, getSupportedBrowsers, generateSearchDirectories, findTailwindConfiguration, loadPostcssConfiguration, } from '@angular/build/private';
|
|
8
|
+
import { normalizeOptimization, normalizeSourceMaps, } from '@angular-devkit/build-angular/src/utils/index.js';
|
|
9
|
+
import { createSharedMappingsPlugin } from './shared-mappings-plugin.js';
|
|
10
|
+
import { createAwaitableCompilerPlugin } from './create-awaitable-compiler-plugin.js';
|
|
11
|
+
export async function createAngularEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, hash = false, chunks, platform, optimizedMappings) {
|
|
12
|
+
const workspaceRoot = context.workspaceRoot;
|
|
13
|
+
const projectMetadata = await context.getProjectMetadata(context.target.project);
|
|
14
|
+
const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
|
|
15
|
+
const browsers = getSupportedBrowsers(projectRoot, context.logger);
|
|
16
|
+
const target = transformSupportedBrowsersToTargets(browsers);
|
|
17
|
+
const optimizationOptions = normalizeOptimization(builderOptions.optimization);
|
|
18
|
+
const sourcemapOptions = normalizeSourceMaps(builderOptions.sourceMap);
|
|
19
|
+
const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]);
|
|
20
|
+
const postcssConfiguration = await loadPostcssConfiguration(searchDirectories);
|
|
21
|
+
const tailwindConfiguration = postcssConfiguration
|
|
22
|
+
? undefined
|
|
23
|
+
: await getTailwindConfig(searchDirectories);
|
|
24
|
+
const outputNames = {
|
|
25
|
+
bundles: '[name]',
|
|
26
|
+
media: 'media/[name]',
|
|
27
|
+
};
|
|
28
|
+
let fileReplacements;
|
|
29
|
+
if (builderOptions.fileReplacements) {
|
|
30
|
+
for (const replacement of builderOptions.fileReplacements) {
|
|
31
|
+
fileReplacements ??= {};
|
|
32
|
+
fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
tsConfigPath = createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings);
|
|
36
|
+
const pluginOptions = {
|
|
37
|
+
sourcemap: !!sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
38
|
+
thirdPartySourcemaps: sourcemapOptions.vendor,
|
|
39
|
+
tsconfig: tsConfigPath,
|
|
40
|
+
jit: false,
|
|
41
|
+
advancedOptimizations: !dev,
|
|
42
|
+
fileReplacements,
|
|
43
|
+
sourceFileCache: cache.bundlerCache,
|
|
44
|
+
loadResultCache: cache.bundlerCache.loadResultCache,
|
|
45
|
+
incremental: true,
|
|
46
|
+
includeTestMetadata: !optimizationOptions.scripts,
|
|
47
|
+
};
|
|
48
|
+
const stylesheetBundlerOptions = {
|
|
49
|
+
workspaceRoot,
|
|
50
|
+
inlineFonts: !!optimizationOptions.fonts.inline,
|
|
51
|
+
optimization: !!optimizationOptions.styles.minify,
|
|
52
|
+
sourcemap:
|
|
53
|
+
// Hidden component stylesheet sourcemaps are inaccessible which is effectively
|
|
54
|
+
// the same as being disabled. Disabling has the advantage of avoiding the overhead
|
|
55
|
+
// of sourcemap processing.
|
|
56
|
+
sourcemapOptions.styles && !sourcemapOptions.hidden ? 'linked' : false,
|
|
57
|
+
outputNames,
|
|
58
|
+
includePaths: builderOptions.stylePreprocessorOptions?.includePaths,
|
|
59
|
+
sass: builderOptions?.stylePreprocessorOptions?.sass,
|
|
60
|
+
externalDependencies: external,
|
|
61
|
+
target,
|
|
62
|
+
inlineStyleLanguage: builderOptions.inlineStyleLanguage ?? 'css',
|
|
63
|
+
preserveSymlinks: builderOptions.preserveSymlinks,
|
|
64
|
+
tailwindConfiguration,
|
|
65
|
+
postcssConfiguration,
|
|
66
|
+
cacheOptions: {
|
|
67
|
+
enabled: true,
|
|
68
|
+
basePath: cache.cachePath,
|
|
69
|
+
path: cache.cachePath,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
|
|
73
|
+
const commonjsPlugin = commonjsPluginModule.default;
|
|
74
|
+
stylesheetBundlerOptions.externalDependencies = [];
|
|
75
|
+
const [compilerPlugin, pluginDisposed] = createAwaitableCompilerPlugin(pluginOptions, stylesheetBundlerOptions);
|
|
76
|
+
const config = {
|
|
77
|
+
entryPoints: entryPoints.map(ep => ({
|
|
78
|
+
in: ep.fileName,
|
|
79
|
+
out: path.parse(ep.outName).name,
|
|
80
|
+
})),
|
|
81
|
+
outdir,
|
|
82
|
+
entryNames: hash ? '[name]-[hash]' : '[name]',
|
|
83
|
+
write: false,
|
|
84
|
+
external,
|
|
85
|
+
logLevel: 'warning',
|
|
86
|
+
bundle: true,
|
|
87
|
+
sourcemap: sourcemapOptions.scripts,
|
|
88
|
+
minify: !dev,
|
|
89
|
+
supported: {
|
|
90
|
+
'async-await': false,
|
|
91
|
+
'object-rest-spread': false,
|
|
92
|
+
},
|
|
93
|
+
splitting: chunks,
|
|
94
|
+
platform: platform ?? 'browser',
|
|
95
|
+
format: 'esm',
|
|
96
|
+
target: target,
|
|
97
|
+
logLimit: 0,
|
|
98
|
+
plugins: [
|
|
99
|
+
compilerPlugin,
|
|
100
|
+
...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
|
|
101
|
+
commonjsPlugin(),
|
|
102
|
+
],
|
|
103
|
+
define: {
|
|
104
|
+
...(!dev ? { ngDevMode: 'false' } : {}),
|
|
105
|
+
ngJitMode: 'false',
|
|
106
|
+
},
|
|
107
|
+
...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
|
|
108
|
+
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
|
|
109
|
+
};
|
|
110
|
+
const ctx = await esbuild.context(config);
|
|
111
|
+
return { ctx, pluginDisposed };
|
|
112
|
+
}
|
|
113
|
+
async function getTailwindConfig(searchDirectories) {
|
|
114
|
+
const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories);
|
|
115
|
+
if (!tailwindConfigurationPath) {
|
|
116
|
+
return undefined;
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
file: tailwindConfigurationPath,
|
|
120
|
+
package: createRequire(tailwindConfigurationPath).resolve('tailwindcss'),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Creates a tsconfig.federation.json that includes the federation entry points.
|
|
125
|
+
*/
|
|
126
|
+
function createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints, optimizedMappings) {
|
|
127
|
+
const fullTsConfigPath = path.join(workspaceRoot, tsConfigPath);
|
|
128
|
+
const tsconfigDir = path.dirname(fullTsConfigPath);
|
|
129
|
+
const tsconfigAsString = fs.readFileSync(fullTsConfigPath, 'utf-8');
|
|
130
|
+
const tsconfig = JSON5.parse(tsconfigAsString);
|
|
131
|
+
tsconfig.files = entryPoints
|
|
132
|
+
.filter(ep => ep.fileName.startsWith('.'))
|
|
133
|
+
.map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
|
|
134
|
+
if (optimizedMappings) {
|
|
135
|
+
const filtered = entryPoints
|
|
136
|
+
.filter(ep => !ep.fileName.startsWith('.'))
|
|
137
|
+
.map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
|
|
138
|
+
if (!tsconfig.include) {
|
|
139
|
+
tsconfig.include = [];
|
|
140
|
+
}
|
|
141
|
+
for (const ep of filtered) {
|
|
142
|
+
if (!tsconfig.include.includes(ep)) {
|
|
143
|
+
tsconfig.include.push(ep);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const content = JSON5.stringify(tsconfig, null, 2);
|
|
148
|
+
const tsconfigFedPath = path.join(tsconfigDir, 'tsconfig.federation.json');
|
|
149
|
+
if (!doesFileExistAndJsonEqual(tsconfigFedPath, content)) {
|
|
150
|
+
fs.writeFileSync(tsconfigFedPath, JSON.stringify(tsconfig, null, 2));
|
|
151
|
+
}
|
|
152
|
+
return tsconfigFedPath;
|
|
153
|
+
}
|
|
154
|
+
function doesFileExistAndJsonEqual(filePath, content) {
|
|
155
|
+
if (!fs.existsSync(filePath)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const currentContent = fs.readFileSync(filePath, 'utf-8');
|
|
160
|
+
const currentJson = JSON5.parse(currentContent);
|
|
161
|
+
const newJson = JSON5.parse(content);
|
|
162
|
+
return isDeepStrictEqual(currentJson, newJson);
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -2,9 +2,9 @@ import { type NFBuildAdapter } from '@softarc/native-federation';
|
|
|
2
2
|
import * as esbuild from 'esbuild';
|
|
3
3
|
import type { BuilderContext } from '@angular-devkit/architect';
|
|
4
4
|
import type { ApplicationBuilderOptions } from '@angular/build';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export declare function
|
|
5
|
+
export interface EsbuildContextResult {
|
|
6
|
+
ctx: esbuild.BuildContext;
|
|
7
|
+
pluginDisposed: Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare function createAngularBuildAdapter(builderOptions: ApplicationBuilderOptions, context: BuilderContext): NFBuildAdapter;
|
|
10
10
|
//# sourceMappingURL=angular-esbuild-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"angular-esbuild-adapter.d.ts","sourceRoot":"","sources":["../../../src/utils/angular-esbuild-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,4BAA4B,CAAC;AAGpC,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAKhE,MAAM,WAAW,oBAAoB;IACnC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AA+FD,wBAAgB,yBAAyB,CACvC,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,GACtB,cAAc,CAqHhB"}
|
|
@@ -1,276 +1,31 @@
|
|
|
1
|
-
import { logger, AbortedError } from '@softarc/native-federation/internal';
|
|
2
|
-
import * as esbuild from 'esbuild';
|
|
3
|
-
import { transformSupportedBrowsersToTargets, getSupportedBrowsers, generateSearchDirectories, findTailwindConfiguration, loadPostcssConfiguration, } from '@angular/build/private';
|
|
4
|
-
import { createCompilerPluginOptions } from './create-compiler-options.js';
|
|
5
|
-
import { normalizeOptimization, normalizeSourceMaps, } from '@angular-devkit/build-angular/src/utils/index.js';
|
|
6
|
-
import { createRequire } from 'node:module';
|
|
7
1
|
import * as fs from 'fs';
|
|
8
2
|
import * as path from 'path';
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// Todo: figure out if still necessary
|
|
17
|
-
export function setMemResultHandler(handler) {
|
|
18
|
-
_memResultHandler = handler;
|
|
19
|
-
}
|
|
20
|
-
export function createAngularBuildAdapter(builderOptions, context, rebuildRequested = new RebuildHubs()) {
|
|
21
|
-
return async (options) => {
|
|
22
|
-
const { entryPoints, tsConfigPath, external, outdir, mappedPaths, kind, watch, dev, hash, chunks, platform, optimizedMappings, signal, } = options;
|
|
23
|
-
setNgServerMode();
|
|
24
|
-
const files = await runEsbuild(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, watch, rebuildRequested, dev, kind, chunks, hash, undefined, undefined, undefined, platform, optimizedMappings, signal);
|
|
25
|
-
if (kind === 'shared-package') {
|
|
26
|
-
const scriptFiles = files.filter(f => f.endsWith('.js') || f.endsWith('.mjs'));
|
|
27
|
-
for (const file of scriptFiles) {
|
|
28
|
-
link(file, !!dev);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
return files.map(fileName => ({ fileName }));
|
|
32
|
-
};
|
|
33
|
-
async function link(outfile, dev) {
|
|
34
|
-
const code = fs.readFileSync(outfile, 'utf-8');
|
|
35
|
-
try {
|
|
36
|
-
const linkerEsm = await loadEsmModule('@angular/compiler-cli/linker/babel');
|
|
37
|
-
const linker = linkerEsm.default;
|
|
38
|
-
const result = await transformAsync(code, {
|
|
39
|
-
filename: outfile,
|
|
40
|
-
compact: !dev,
|
|
41
|
-
configFile: false,
|
|
42
|
-
babelrc: false,
|
|
43
|
-
minified: !dev,
|
|
44
|
-
browserslistConfigFile: false,
|
|
45
|
-
plugins: [linker],
|
|
46
|
-
});
|
|
47
|
-
if (!result)
|
|
48
|
-
logger.warn(`File ${outfile} could not be linked.`);
|
|
49
|
-
if (!result?.code) {
|
|
50
|
-
logger.warn(`File ${outfile} seems to be empty.`);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
fs.writeFileSync(outfile, result.code, 'utf-8');
|
|
54
|
-
}
|
|
55
|
-
catch (e) {
|
|
56
|
-
logger.error('error linking');
|
|
57
|
-
if (fs.existsSync(`${outfile}.error`)) {
|
|
58
|
-
fs.unlinkSync(`${outfile}.error`);
|
|
59
|
-
}
|
|
60
|
-
fs.renameSync(outfile, `${outfile}.error`);
|
|
61
|
-
throw e;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
async function runEsbuild(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, watch, rebuildRequested = new RebuildHubs(), dev, kind, chunks, hash = false, plugins = null, absWorkingDir = undefined, logLevel = 'warning', platform, optimizedMappings, signal) {
|
|
66
|
-
if (signal?.aborted) {
|
|
67
|
-
throw new AbortedError('[angular-esbuild-adapter] Before building');
|
|
68
|
-
}
|
|
69
|
-
const workspaceRoot = context.workspaceRoot;
|
|
70
|
-
const projectMetadata = await context.getProjectMetadata(context.target.project);
|
|
71
|
-
const projectRoot = path.join(workspaceRoot, projectMetadata['root'] ?? '');
|
|
72
|
-
const browsers = getSupportedBrowsers(projectRoot, context.logger);
|
|
73
|
-
const target = transformSupportedBrowsersToTargets(browsers);
|
|
74
|
-
const optimizationOptions = normalizeOptimization(builderOptions.optimization);
|
|
75
|
-
const sourcemapOptions = normalizeSourceMaps(builderOptions.sourceMap);
|
|
76
|
-
const searchDirectories = await generateSearchDirectories([projectRoot, workspaceRoot]);
|
|
77
|
-
const postcssConfiguration = await loadPostcssConfiguration(searchDirectories);
|
|
78
|
-
const tailwindConfiguration = postcssConfiguration
|
|
79
|
-
? undefined
|
|
80
|
-
: await getTailwindConfig(searchDirectories);
|
|
81
|
-
const outputNames = {
|
|
82
|
-
bundles: '[name]',
|
|
83
|
-
media: 'media/[name]',
|
|
84
|
-
};
|
|
85
|
-
let fileReplacements;
|
|
86
|
-
if (builderOptions.fileReplacements) {
|
|
87
|
-
for (const replacement of builderOptions.fileReplacements) {
|
|
88
|
-
fileReplacements ??= {};
|
|
89
|
-
fileReplacements[path.join(workspaceRoot, replacement.replace)] = path.join(workspaceRoot, replacement.with);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (!optimizedMappings) {
|
|
93
|
-
tsConfigPath = createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints);
|
|
94
|
-
}
|
|
95
|
-
const pluginOptions = createCompilerPluginOptions({
|
|
96
|
-
workspaceRoot,
|
|
97
|
-
optimizationOptions,
|
|
98
|
-
sourcemapOptions,
|
|
99
|
-
tsconfig: tsConfigPath,
|
|
100
|
-
outputNames,
|
|
101
|
-
fileReplacements,
|
|
102
|
-
externalDependencies: external,
|
|
103
|
-
preserveSymlinks: builderOptions.preserveSymlinks,
|
|
104
|
-
stylePreprocessorOptions: builderOptions.stylePreprocessorOptions,
|
|
105
|
-
advancedOptimizations: !dev,
|
|
106
|
-
inlineStyleLanguage: builderOptions.inlineStyleLanguage,
|
|
107
|
-
jit: false,
|
|
108
|
-
tailwindConfiguration,
|
|
109
|
-
postcssConfiguration,
|
|
110
|
-
}, target, undefined);
|
|
111
|
-
const commonjsPluginModule = await import('@chialab/esbuild-plugin-commonjs');
|
|
112
|
-
const commonjsPlugin = commonjsPluginModule.default;
|
|
113
|
-
pluginOptions.styleOptions.externalDependencies = [];
|
|
114
|
-
const [compilerPlugin, pluginDisposed] = createAwaitableCompilerPlugin(pluginOptions.pluginOptions, pluginOptions.styleOptions);
|
|
115
|
-
const config = {
|
|
116
|
-
entryPoints: entryPoints.map(ep => ({
|
|
117
|
-
in: ep.fileName,
|
|
118
|
-
out: path.parse(ep.outName).name,
|
|
119
|
-
})),
|
|
120
|
-
outdir,
|
|
121
|
-
entryNames: hash ? '[name]-[hash]' : '[name]',
|
|
122
|
-
write: false,
|
|
123
|
-
absWorkingDir,
|
|
124
|
-
external,
|
|
125
|
-
logLevel,
|
|
126
|
-
bundle: true,
|
|
127
|
-
sourcemap: sourcemapOptions.scripts,
|
|
128
|
-
minify: !dev,
|
|
129
|
-
supported: {
|
|
130
|
-
'async-await': false,
|
|
131
|
-
'object-rest-spread': false,
|
|
132
|
-
},
|
|
133
|
-
splitting: chunks, //kind === 'mapping-or-exposed',
|
|
134
|
-
platform: platform ?? 'browser',
|
|
135
|
-
format: 'esm',
|
|
136
|
-
target: target,
|
|
137
|
-
logLimit: kind === 'shared-package' ? 1 : 0,
|
|
138
|
-
plugins: plugins || [
|
|
139
|
-
compilerPlugin,
|
|
140
|
-
...(mappedPaths && mappedPaths.length > 0 ? [createSharedMappingsPlugin(mappedPaths)] : []),
|
|
141
|
-
commonjsPlugin(),
|
|
142
|
-
],
|
|
143
|
-
define: {
|
|
144
|
-
...(!dev ? { ngDevMode: 'false' } : {}),
|
|
145
|
-
ngJitMode: 'false',
|
|
146
|
-
},
|
|
147
|
-
...(builderOptions.loader ? { loader: builderOptions.loader } : {}),
|
|
148
|
-
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js', '.cjs'],
|
|
149
|
-
};
|
|
150
|
-
const ctx = await esbuild.context(config);
|
|
151
|
-
try {
|
|
152
|
-
const abortHandler = async () => {
|
|
153
|
-
await ctx.cancel();
|
|
154
|
-
await ctx.dispose();
|
|
155
|
-
await pluginDisposed;
|
|
156
|
-
};
|
|
157
|
-
if (signal) {
|
|
158
|
-
signal.addEventListener('abort', abortHandler, { once: true });
|
|
159
|
-
}
|
|
160
|
-
const result = await ctx.rebuild();
|
|
161
|
-
const memOnly = dev && kind === 'mapping-or-exposed' && !!_memResultHandler;
|
|
162
|
-
const writtenFiles = writeResult(result, outdir, !!memOnly);
|
|
163
|
-
if (watch) {
|
|
164
|
-
// Also hardcoded disabled?
|
|
165
|
-
registerForRebuilds(kind ?? 'shared-package', rebuildRequested, ctx, outdir, !!memOnly);
|
|
166
|
-
}
|
|
167
|
-
else {
|
|
168
|
-
if (signal)
|
|
169
|
-
signal.removeEventListener('abort', abortHandler);
|
|
170
|
-
await ctx.dispose();
|
|
171
|
-
await pluginDisposed;
|
|
172
|
-
}
|
|
173
|
-
return writtenFiles;
|
|
174
|
-
}
|
|
175
|
-
catch (error) {
|
|
176
|
-
// ESBuild throws an error if the request is cancelled.
|
|
177
|
-
// if it is, it's changed to an 'AbortedError'
|
|
178
|
-
if (signal?.aborted && error instanceof Error && error.message.includes('canceled')) {
|
|
179
|
-
throw new AbortedError('[runEsbuild] ESBuild was canceled.');
|
|
180
|
-
}
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
async function getTailwindConfig(searchDirectories) {
|
|
185
|
-
const tailwindConfigurationPath = findTailwindConfiguration(searchDirectories);
|
|
186
|
-
if (!tailwindConfigurationPath) {
|
|
187
|
-
return undefined;
|
|
188
|
-
}
|
|
189
|
-
return {
|
|
190
|
-
file: tailwindConfigurationPath,
|
|
191
|
-
package: createRequire(tailwindConfigurationPath).resolve('tailwindcss'),
|
|
192
|
-
};
|
|
193
|
-
}
|
|
194
|
-
function createTsConfigForFederation(workspaceRoot, tsConfigPath, entryPoints) {
|
|
195
|
-
const fullTsConfigPath = path.join(workspaceRoot, tsConfigPath);
|
|
196
|
-
const tsconfigDir = path.dirname(fullTsConfigPath);
|
|
197
|
-
const filtered = entryPoints
|
|
198
|
-
.filter(ep => !ep.fileName.includes('/node_modules/') && !ep.fileName.startsWith('.'))
|
|
199
|
-
.map(ep => path.relative(tsconfigDir, ep.fileName).replace(/\\\\/g, '/'));
|
|
200
|
-
const tsconfigAsString = fs.readFileSync(fullTsConfigPath, 'utf-8');
|
|
201
|
-
const tsconfig = JSON5.parse(tsconfigAsString);
|
|
202
|
-
if (!tsconfig.include) {
|
|
203
|
-
tsconfig.include = [];
|
|
204
|
-
}
|
|
205
|
-
for (const ep of filtered) {
|
|
206
|
-
if (!tsconfig.include.includes(ep)) {
|
|
207
|
-
tsconfig.include.push(ep);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
const content = JSON5.stringify(tsconfig, null, 2);
|
|
211
|
-
const tsconfigFedPath = path.join(tsconfigDir, 'tsconfig.federation.json');
|
|
212
|
-
if (!doesFileExistAndJsonEqual(tsconfigFedPath, content)) {
|
|
213
|
-
fs.writeFileSync(tsconfigFedPath, JSON.stringify(tsconfig, null, 2));
|
|
214
|
-
}
|
|
215
|
-
tsConfigPath = tsconfigFedPath;
|
|
216
|
-
return tsConfigPath;
|
|
217
|
-
}
|
|
218
|
-
/**
|
|
219
|
-
* Checks if a file exists and if its content is equal to the provided content.
|
|
220
|
-
* If the file does not exist, it returns false.
|
|
221
|
-
* If the file or its content is invalid JSON, it returns false.
|
|
222
|
-
* @param {string} path - The path to the file
|
|
223
|
-
* @param {string} content - The content to compare with
|
|
224
|
-
* @returns {boolean} - Returns true if the file exists and its content is equal to the provided content
|
|
225
|
-
*/
|
|
226
|
-
function doesFileExistAndJsonEqual(path, content) {
|
|
227
|
-
if (!fs.existsSync(path)) {
|
|
228
|
-
return false;
|
|
229
|
-
}
|
|
230
|
-
try {
|
|
231
|
-
const currentContent = fs.readFileSync(path, 'utf-8');
|
|
232
|
-
const currentJson = JSON5.parse(currentContent);
|
|
233
|
-
const newJson = JSON5.parse(content);
|
|
234
|
-
return isDeepStrictEqual(currentJson, newJson);
|
|
235
|
-
}
|
|
236
|
-
catch {
|
|
237
|
-
return false;
|
|
3
|
+
import { AbortedError } from '@softarc/native-federation/internal';
|
|
4
|
+
import * as esbuild from 'esbuild';
|
|
5
|
+
import { createAngularEsbuildContext } from './angular-bundler.js';
|
|
6
|
+
import { createNodeModulesEsbuildContext } from './node-modules-bundler.js';
|
|
7
|
+
async function createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, isNodeModules, hash = false, chunks, platform, optimizedMappings) {
|
|
8
|
+
if (isNodeModules) {
|
|
9
|
+
return createNodeModulesEsbuildContext(builderOptions, context, entryPoints, external, outdir, mappedPaths, cache, dev, hash, chunks, platform);
|
|
238
10
|
}
|
|
11
|
+
return createAngularEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, hash, chunks, platform, optimizedMappings);
|
|
239
12
|
}
|
|
240
|
-
function writeResult(result, outdir
|
|
13
|
+
function writeResult(result, outdir) {
|
|
241
14
|
const writtenFiles = [];
|
|
242
|
-
if (memOnly) {
|
|
243
|
-
_memResultHandler(result.outputFiles ?? [], outdir);
|
|
244
|
-
}
|
|
245
15
|
for (const outFile of result.outputFiles ?? []) {
|
|
246
16
|
const fileName = path.basename(outFile.path);
|
|
247
17
|
const filePath = path.join(outdir, fileName);
|
|
248
|
-
|
|
249
|
-
fs.writeFileSync(filePath, outFile.text);
|
|
250
|
-
}
|
|
18
|
+
fs.writeFileSync(filePath, outFile.text);
|
|
251
19
|
writtenFiles.push(filePath);
|
|
252
20
|
}
|
|
253
|
-
if (!memOnly) {
|
|
254
|
-
// for (const asset of result.outputFiles)
|
|
255
|
-
}
|
|
256
21
|
return writtenFiles;
|
|
257
22
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
export function loadEsmModule(modulePath) {
|
|
267
|
-
return new Function('modulePath', `return import(modulePath);`)(modulePath);
|
|
268
|
-
}
|
|
269
|
-
//
|
|
270
|
-
// Usually, ngServerMode is set during bundling. However, we need to infer this
|
|
271
|
-
// value at runtime as we are using the same shared bundle for @angular/core
|
|
272
|
-
// on the server and in the browser.
|
|
273
|
-
//
|
|
23
|
+
/**
|
|
24
|
+
* Patches @angular/core to infer ngServerMode at runtime.
|
|
25
|
+
* Usually, ngServerMode is set during bundling. However, we need to infer this
|
|
26
|
+
* value at runtime as we are using the same shared bundle for @angular/core
|
|
27
|
+
* on the server and in the browser.
|
|
28
|
+
*/
|
|
274
29
|
function setNgServerMode() {
|
|
275
30
|
const fileToPatch = 'node_modules/@angular/core/fesm2022/core.mjs';
|
|
276
31
|
const lineToAdd = `if (typeof globalThis.ngServerMode ==='undefined') globalThis.ngServerMode = (typeof window === 'undefined') ? true : false;`;
|
|
@@ -287,3 +42,68 @@ function setNgServerMode() {
|
|
|
287
42
|
console.error('Error patching file ', fileToPatch, '\nIs it write-protected?');
|
|
288
43
|
}
|
|
289
44
|
}
|
|
45
|
+
export function createAngularBuildAdapter(builderOptions, context) {
|
|
46
|
+
const bundleContextCache = new Map();
|
|
47
|
+
const dispose = async (name) => {
|
|
48
|
+
if (name) {
|
|
49
|
+
if (!bundleContextCache.has(name))
|
|
50
|
+
throw new Error(`Could not dispose of non-existing build '${name}'`);
|
|
51
|
+
const entry = bundleContextCache.get(name);
|
|
52
|
+
await entry.ctx.dispose();
|
|
53
|
+
await entry.pluginDisposed;
|
|
54
|
+
bundleContextCache.delete(name);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const disposals = [];
|
|
58
|
+
for (const [, entry] of bundleContextCache) {
|
|
59
|
+
disposals.push((async () => {
|
|
60
|
+
await entry.ctx.dispose();
|
|
61
|
+
await entry.pluginDisposed;
|
|
62
|
+
})());
|
|
63
|
+
}
|
|
64
|
+
bundleContextCache.clear();
|
|
65
|
+
await Promise.all(disposals);
|
|
66
|
+
await esbuild.stop();
|
|
67
|
+
};
|
|
68
|
+
const setup = async (options) => {
|
|
69
|
+
const { entryPoints, tsConfigPath, external, outdir, mappedPaths, bundleName, isNodeModules, dev, chunks, hash, platform, optimizedMappings, cache, } = options;
|
|
70
|
+
setNgServerMode();
|
|
71
|
+
if (bundleContextCache.has(bundleName)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const { ctx, pluginDisposed } = await createEsbuildContext(builderOptions, context, entryPoints, external, outdir, tsConfigPath, mappedPaths, cache, dev, isNodeModules, hash, chunks, platform, optimizedMappings);
|
|
75
|
+
bundleContextCache.set(bundleName, {
|
|
76
|
+
ctx,
|
|
77
|
+
pluginDisposed,
|
|
78
|
+
outdir,
|
|
79
|
+
cache,
|
|
80
|
+
isNodeModules,
|
|
81
|
+
dev: !!dev,
|
|
82
|
+
name: bundleName,
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
const build = async (name, opts = {}) => {
|
|
86
|
+
const bundleContext = bundleContextCache.get(name);
|
|
87
|
+
if (!bundleContext) {
|
|
88
|
+
throw new Error(`No context found for build "${name}". Call setup() first.`);
|
|
89
|
+
}
|
|
90
|
+
if (opts?.signal?.aborted) {
|
|
91
|
+
throw new AbortedError('[build] Aborted before rebuild');
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
if (opts.files) {
|
|
95
|
+
bundleContext.cache.bundlerCache.invalidate(new Set(opts.files));
|
|
96
|
+
}
|
|
97
|
+
const result = await bundleContext.ctx.rebuild();
|
|
98
|
+
const writtenFiles = writeResult(result, bundleContext.outdir);
|
|
99
|
+
return writtenFiles.map(fileName => ({ fileName }));
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (opts?.signal?.aborted && error instanceof Error && error.message.includes('canceled')) {
|
|
103
|
+
throw new AbortedError('[build] ESBuild rebuild was canceled.');
|
|
104
|
+
}
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
return { setup, build, dispose };
|
|
109
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as esbuild from 'esbuild';
|
|
2
|
+
import { type SourceFileCache } from '@angular/build/private';
|
|
3
|
+
import type { BuilderContext } from '@angular-devkit/architect';
|
|
4
|
+
import type { ApplicationBuilderOptions } from '@angular/build';
|
|
5
|
+
import type { EntryPoint, FederationCache } from '@softarc/native-federation';
|
|
6
|
+
import type { MappedPath } from '@softarc/native-federation/internal';
|
|
7
|
+
export interface NodeModulesBundleResult {
|
|
8
|
+
ctx: esbuild.BuildContext;
|
|
9
|
+
pluginDisposed: Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createNodeModulesEsbuildContext(builderOptions: ApplicationBuilderOptions, context: BuilderContext, entryPoints: EntryPoint[], external: string[], outdir: string, mappedPaths: MappedPath[], cache: FederationCache<SourceFileCache>, dev?: boolean, hash?: boolean, chunks?: boolean, platform?: 'browser' | 'node'): Promise<NodeModulesBundleResult>;
|
|
12
|
+
//# sourceMappingURL=node-modules-bundler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-modules-bundler.d.ts","sourceRoot":"","sources":["../../../src/utils/node-modules-bundler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAInC,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAwDtE,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,OAAO,CAAC,YAAY,CAAC;IAC1B,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAaD,wBAAsB,+BAA+B,CACnD,cAAc,EAAE,yBAAyB,EACzC,OAAO,EAAE,cAAc,EACvB,WAAW,EAAE,UAAU,EAAE,EACzB,QAAQ,EAAE,MAAM,EAAE,EAClB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,EAAE,eAAe,CAAC,eAAe,CAAC,EACvC,GAAG,CAAC,EAAE,OAAO,EACb,IAAI,GAAE,OAAe,EACrB,MAAM,CAAC,EAAE,OAAO,EAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,MAAM,GAC5B,OAAO,CAAC,uBAAuB,CAAC,CA4ElC"}
|