@analogjs/vite-plugin-angular 2.0.0-alpha.9 → 2.0.0-beta.2
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/package.json +9 -5
- package/src/index.d.ts +0 -2
- package/src/index.js +0 -2
- package/src/index.js.map +1 -1
- package/src/lib/angular-pending-tasks.plugin.js +2 -1
- package/src/lib/angular-pending-tasks.plugin.js.map +1 -1
- package/src/lib/angular-storybook-plugin.d.ts +2 -2
- package/src/lib/angular-storybook-plugin.js +11 -4
- package/src/lib/angular-storybook-plugin.js.map +1 -1
- package/src/lib/angular-vite-plugin.d.ts +13 -23
- package/src/lib/angular-vite-plugin.js +190 -214
- package/src/lib/angular-vite-plugin.js.map +1 -1
- package/src/lib/component-resolvers.js +1 -1
- package/src/lib/component-resolvers.js.map +1 -1
- package/src/lib/host.d.ts +0 -5
- package/src/lib/host.js +5 -80
- package/src/lib/host.js.map +1 -1
- package/src/lib/live-reload-plugin.d.ts +6 -0
- package/src/lib/live-reload-plugin.js +63 -0
- package/src/lib/live-reload-plugin.js.map +1 -0
- package/src/lib/models.d.ts +11 -0
- package/src/lib/models.js +2 -0
- package/src/lib/models.js.map +1 -0
- package/src/lib/nx-folder-plugin.d.ts +7 -0
- package/src/lib/nx-folder-plugin.js +18 -0
- package/src/lib/nx-folder-plugin.js.map +1 -0
- package/src/lib/plugins/file-replacements.plugin.d.ts +12 -0
- package/src/lib/plugins/file-replacements.plugin.js +64 -0
- package/src/lib/plugins/file-replacements.plugin.js.map +1 -0
- package/src/lib/tools/README.md +3 -0
- package/src/lib/tools/builders.json +15 -0
- package/src/lib/tools/package.json +8 -0
- package/src/lib/tools/src/builders/vite/schema.d.ts +6 -0
- package/src/lib/tools/src/builders/vite/schema.json +39 -0
- package/src/lib/tools/src/builders/vite/vite-build.impl.d.ts +2 -0
- package/src/lib/tools/src/builders/vite/vite-build.impl.js +38 -0
- package/src/lib/tools/src/builders/vite/vite-build.impl.js.map +1 -0
- package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.d.ts +2 -0
- package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js +62 -0
- package/src/lib/tools/src/builders/vite-dev-server/dev-server.impl.js.map +1 -0
- package/src/lib/tools/src/builders/vite-dev-server/schema.d.ts +5 -0
- package/src/lib/tools/src/builders/vite-dev-server/schema.json +25 -0
- package/src/lib/tools/src/index.d.ts +0 -0
- package/src/lib/tools/src/index.js +1 -0
- package/src/lib/tools/src/index.js.map +1 -0
- package/src/lib/utils/devkit.js +3 -11
- package/src/lib/utils/devkit.js.map +1 -1
- package/src/lib/utils/hmr-candidates.js +40 -12
- package/src/lib/utils/hmr-candidates.js.map +1 -1
- package/esbuild.d.ts +0 -3
- package/esbuild.js +0 -31
- package/esbuild.js.map +0 -1
- package/src/lib/authoring/analog.d.ts +0 -1
- package/src/lib/authoring/analog.js +0 -550
- package/src/lib/authoring/analog.js.map +0 -1
- package/src/lib/authoring/constants.d.ts +0 -26
- package/src/lib/authoring/constants.js +0 -47
- package/src/lib/authoring/constants.js.map +0 -1
- package/src/lib/authoring/frontmatter.d.ts +0 -2
- package/src/lib/authoring/frontmatter.js +0 -26
- package/src/lib/authoring/frontmatter.js.map +0 -1
- package/src/lib/authoring/markdown-transform.d.ts +0 -4
- package/src/lib/authoring/markdown-transform.js +0 -19
- package/src/lib/authoring/markdown-transform.js.map +0 -1
- package/src/lib/authoring/marked-setup.service.d.ts +0 -23
- package/src/lib/authoring/marked-setup.service.js +0 -118
- package/src/lib/authoring/marked-setup.service.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { dirname, relative, resolve } from 'node:path';
|
|
1
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, } from 'node:path';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
3
|
import * as compilerCli from '@angular/compiler-cli';
|
|
3
|
-
import * as ts from 'typescript';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
|
-
import { normalizePath, preprocessCSS, } from 'vite';
|
|
5
|
+
import { normalizePath, preprocessCSS, defaultClientConditions, } from 'vite';
|
|
6
6
|
import * as ngCompiler from '@angular/compiler';
|
|
7
7
|
import { createCompilerPlugin } from './compiler-plugin.js';
|
|
8
8
|
import { StyleUrlsResolver, TemplateUrlsResolver, } from './component-resolvers.js';
|
|
@@ -13,18 +13,17 @@ import { createJitResourceTransformer, SourceFileCache, angularMajor, } from './
|
|
|
13
13
|
import { angularVitestPlugins } from './angular-vitest-plugin.js';
|
|
14
14
|
import { angularStorybookPlugin } from './angular-storybook-plugin.js';
|
|
15
15
|
const require = createRequire(import.meta.url);
|
|
16
|
-
import { getFrontmatterMetadata } from './authoring/frontmatter.js';
|
|
17
|
-
import { defaultMarkdownTemplateTransforms, } from './authoring/markdown-transform.js';
|
|
18
16
|
import { routerPlugin } from './router-plugin.js';
|
|
19
17
|
import { pendingTasksPlugin } from './angular-pending-tasks.plugin.js';
|
|
20
|
-
import {
|
|
18
|
+
import { liveReloadPlugin } from './live-reload-plugin.js';
|
|
19
|
+
import { nxFolderPlugin } from './nx-folder-plugin.js';
|
|
20
|
+
import { replaceFiles, } from './plugins/file-replacements.plugin.js';
|
|
21
21
|
/**
|
|
22
22
|
* TypeScript file extension regex
|
|
23
23
|
* Match .(c or m)ts, .ts extensions with an optional ? for query params
|
|
24
24
|
* Ignore .tsx extensions
|
|
25
25
|
*/
|
|
26
26
|
const TS_EXT_REGEX = /\.[cm]?(ts|analog|ag)[^x]?\??/;
|
|
27
|
-
const ANGULAR_COMPONENT_PREFIX = '/@ng/component';
|
|
28
27
|
const classNames = new Map();
|
|
29
28
|
export function angular(options) {
|
|
30
29
|
/**
|
|
@@ -32,10 +31,7 @@ export function angular(options) {
|
|
|
32
31
|
* are used for values not provided.
|
|
33
32
|
*/
|
|
34
33
|
const pluginOptions = {
|
|
35
|
-
tsconfig: options?.tsconfig
|
|
36
|
-
(process.env['NODE_ENV'] === 'test'
|
|
37
|
-
? './tsconfig.spec.json'
|
|
38
|
-
: './tsconfig.app.json'),
|
|
34
|
+
tsconfig: options?.tsconfig || '',
|
|
39
35
|
workspaceRoot: options?.workspaceRoot ?? process.cwd(),
|
|
40
36
|
inlineStylesExtension: options?.inlineStylesExtension ?? 'css',
|
|
41
37
|
advanced: {
|
|
@@ -46,24 +42,14 @@ export function angular(options) {
|
|
|
46
42
|
},
|
|
47
43
|
},
|
|
48
44
|
supportedBrowsers: options?.supportedBrowsers ?? ['safari 15'],
|
|
49
|
-
jit: options?.
|
|
50
|
-
supportAnalogFormat: options?.experimental?.supportAnalogFormat ?? false,
|
|
51
|
-
markdownTemplateTransforms: options?.experimental
|
|
52
|
-
?.markdownTemplateTransforms?.length
|
|
53
|
-
? options.experimental.markdownTemplateTransforms
|
|
54
|
-
: defaultMarkdownTemplateTransforms,
|
|
45
|
+
jit: options?.jit,
|
|
55
46
|
include: options?.include ?? [],
|
|
56
47
|
additionalContentDirs: options?.additionalContentDirs ?? [],
|
|
57
48
|
liveReload: options?.liveReload ?? false,
|
|
58
49
|
disableTypeChecking: options?.disableTypeChecking ?? true,
|
|
50
|
+
fileReplacements: options?.fileReplacements ?? [],
|
|
59
51
|
};
|
|
60
|
-
// The file emitter created during `onStart` that will be used during the build in `onLoad` callbacks for TS files
|
|
61
|
-
let fileEmitter;
|
|
62
|
-
let compilerOptions = {};
|
|
63
|
-
const ts = require('typescript');
|
|
64
52
|
let resolvedConfig;
|
|
65
|
-
let rootNames;
|
|
66
|
-
let host;
|
|
67
53
|
let nextProgram;
|
|
68
54
|
let builderProgram;
|
|
69
55
|
let watchMode = false;
|
|
@@ -72,6 +58,7 @@ export function angular(options) {
|
|
|
72
58
|
let externalComponentStyles;
|
|
73
59
|
const sourceFileCache = new SourceFileCache();
|
|
74
60
|
const isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST'];
|
|
61
|
+
const isVitestVscode = !!process.env['VITEST_VSCODE'];
|
|
75
62
|
const isStackBlitz = !!process.versions['webcontainer'];
|
|
76
63
|
const isAstroIntegration = process.env['ANALOG_ASTRO'] === 'true';
|
|
77
64
|
const isStorybook = process.env['npm_lifecycle_script']?.includes('storybook') ||
|
|
@@ -80,9 +67,16 @@ export function angular(options) {
|
|
|
80
67
|
process.env['ANALOG_STORYBOOK'] === 'true';
|
|
81
68
|
const jit = typeof pluginOptions?.jit !== 'undefined' ? pluginOptions.jit : isTest;
|
|
82
69
|
let viteServer;
|
|
83
|
-
let styleTransform;
|
|
84
70
|
const styleUrlsResolver = new StyleUrlsResolver();
|
|
85
71
|
const templateUrlsResolver = new TemplateUrlsResolver();
|
|
72
|
+
let outputFile;
|
|
73
|
+
const outputFiles = new Map();
|
|
74
|
+
const fileEmitter = (file) => {
|
|
75
|
+
outputFile?.(file);
|
|
76
|
+
return outputFiles.get(normalizePath(file));
|
|
77
|
+
};
|
|
78
|
+
let initialCompilation = false;
|
|
79
|
+
const declarationFiles = [];
|
|
86
80
|
function angularPlugin() {
|
|
87
81
|
let isProd = false;
|
|
88
82
|
if (angularMajor < 19 || isTest) {
|
|
@@ -90,21 +84,12 @@ export function angular(options) {
|
|
|
90
84
|
}
|
|
91
85
|
return {
|
|
92
86
|
name: '@analogjs/vite-plugin-angular',
|
|
93
|
-
async watchChange() {
|
|
94
|
-
if (isTest) {
|
|
95
|
-
await buildAndAnalyze();
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
87
|
async config(config, { command }) {
|
|
99
88
|
watchMode = command === 'serve';
|
|
100
89
|
isProd =
|
|
101
90
|
config.mode === 'production' ||
|
|
102
91
|
process.env['NODE_ENV'] === 'production';
|
|
103
|
-
pluginOptions.tsconfig =
|
|
104
|
-
options?.tsconfig ??
|
|
105
|
-
resolve(config.root || '.', process.env['NODE_ENV'] === 'test'
|
|
106
|
-
? './tsconfig.spec.json'
|
|
107
|
-
: './tsconfig.app.json');
|
|
92
|
+
pluginOptions.tsconfig = getTsConfigPath(config.root || '.', pluginOptions, isProd, isTest, !!config?.build?.lib);
|
|
108
93
|
return {
|
|
109
94
|
esbuild: config.esbuild ?? false,
|
|
110
95
|
optimizeDeps: {
|
|
@@ -128,7 +113,10 @@ export function angular(options) {
|
|
|
128
113
|
},
|
|
129
114
|
},
|
|
130
115
|
resolve: {
|
|
131
|
-
conditions: [
|
|
116
|
+
conditions: [
|
|
117
|
+
'style',
|
|
118
|
+
...(config.resolve?.conditions || defaultClientConditions),
|
|
119
|
+
],
|
|
132
120
|
},
|
|
133
121
|
};
|
|
134
122
|
},
|
|
@@ -149,76 +137,30 @@ export function angular(options) {
|
|
|
149
137
|
configureServer(server) {
|
|
150
138
|
viteServer = server;
|
|
151
139
|
server.watcher.on('add', async () => {
|
|
152
|
-
|
|
153
|
-
await buildAndAnalyze();
|
|
140
|
+
await performCompilation(resolvedConfig);
|
|
154
141
|
});
|
|
155
142
|
server.watcher.on('unlink', async () => {
|
|
156
|
-
|
|
157
|
-
await buildAndAnalyze();
|
|
143
|
+
await performCompilation(resolvedConfig);
|
|
158
144
|
});
|
|
159
|
-
if (pluginOptions.liveReload) {
|
|
160
|
-
const angularComponentMiddleware = async (req, res, next) => {
|
|
161
|
-
if (req.url === undefined || res.writableEnded) {
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
if (!req.url.includes(ANGULAR_COMPONENT_PREFIX)) {
|
|
165
|
-
next();
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
const requestUrl = new URL(req.url, 'http://localhost');
|
|
169
|
-
const componentId = requestUrl.searchParams.get('c');
|
|
170
|
-
if (!componentId) {
|
|
171
|
-
res.statusCode = 400;
|
|
172
|
-
res.end();
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
const [fileId] = decodeURIComponent(componentId).split('@');
|
|
176
|
-
const resolvedId = resolve(process.cwd(), fileId);
|
|
177
|
-
const invalidated = !!server.moduleGraph.getModuleById(resolvedId)
|
|
178
|
-
?.lastInvalidationTimestamp && classNames.get(resolvedId);
|
|
179
|
-
// don't send an HMR update until the file has been invalidated
|
|
180
|
-
if (!invalidated) {
|
|
181
|
-
res.setHeader('Content-Type', 'text/javascript');
|
|
182
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
183
|
-
res.end('');
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
const result = await fileEmitter?.(resolvedId);
|
|
187
|
-
res.setHeader('Content-Type', 'text/javascript');
|
|
188
|
-
res.setHeader('Cache-Control', 'no-cache');
|
|
189
|
-
res.end(`${result?.hmrUpdateCode || ''}`);
|
|
190
|
-
};
|
|
191
|
-
viteServer.middlewares.use(angularComponentMiddleware);
|
|
192
|
-
}
|
|
193
145
|
},
|
|
194
146
|
async buildStart() {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
147
|
+
// Defer the first compilation in test mode
|
|
148
|
+
if (!isVitestVscode) {
|
|
149
|
+
const { host } = await performCompilation(resolvedConfig);
|
|
150
|
+
initialCompilation = true;
|
|
151
|
+
// Only store cache if in watch mode
|
|
152
|
+
if (watchMode) {
|
|
153
|
+
augmentHostWithCaching(host, sourceFileCache);
|
|
154
|
+
}
|
|
199
155
|
}
|
|
200
|
-
await buildAndAnalyze();
|
|
201
156
|
},
|
|
202
157
|
async handleHotUpdate(ctx) {
|
|
203
|
-
// The `handleHotUpdate` hook may be called before the `buildStart`,
|
|
204
|
-
// which sets the compilation. As a result, the `host` may not be available
|
|
205
|
-
// yet for use, leading to build errors such as "cannot read properties of undefined"
|
|
206
|
-
// (because `host` is undefined).
|
|
207
|
-
if (!host) {
|
|
208
|
-
return;
|
|
209
|
-
}
|
|
210
158
|
if (TS_EXT_REGEX.test(ctx.file)) {
|
|
211
159
|
let [fileId] = ctx.file.split('?');
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
fileId += '.ts';
|
|
215
|
-
}
|
|
216
|
-
const stale = sourceFileCache.get(fileId);
|
|
217
|
-
sourceFileCache.invalidate([fileId]);
|
|
218
|
-
await buildAndAnalyze();
|
|
219
|
-
const result = await fileEmitter?.(fileId, stale);
|
|
160
|
+
await performCompilation(resolvedConfig, [fileId]);
|
|
161
|
+
const result = fileEmitter(fileId);
|
|
220
162
|
if (pluginOptions.liveReload &&
|
|
221
|
-
|
|
163
|
+
result?.hmrEligible &&
|
|
222
164
|
classNames.get(fileId)) {
|
|
223
165
|
const relativeFileId = `${relative(process.cwd(), fileId)}@${classNames.get(fileId)}`;
|
|
224
166
|
sendHMRComponentUpdate(ctx.server, relativeFileId);
|
|
@@ -236,7 +178,8 @@ export function angular(options) {
|
|
|
236
178
|
* for an external resource (styles, html).
|
|
237
179
|
*/
|
|
238
180
|
const isDirect = ctx.modules.find((mod) => ctx.file === mod.file && mod.id?.includes('?direct'));
|
|
239
|
-
|
|
181
|
+
const isInline = ctx.modules.find((mod) => ctx.file === mod.file && mod.id?.includes('?inline'));
|
|
182
|
+
if (isDirect || isInline) {
|
|
240
183
|
if (pluginOptions.liveReload && isDirect?.id && isDirect.file) {
|
|
241
184
|
const isComponentStyle = isDirect.type === 'css' && isComponentStyleSheet(isDirect.id);
|
|
242
185
|
if (isComponentStyle) {
|
|
@@ -287,7 +230,10 @@ export function angular(options) {
|
|
|
287
230
|
}
|
|
288
231
|
});
|
|
289
232
|
});
|
|
290
|
-
await
|
|
233
|
+
await performCompilation(resolvedConfig, [
|
|
234
|
+
...mods.map((mod) => mod.id),
|
|
235
|
+
...updates,
|
|
236
|
+
]);
|
|
291
237
|
if (updates.length > 0) {
|
|
292
238
|
updates.forEach((updateId) => {
|
|
293
239
|
const impRelativeFileId = `${relative(process.cwd(), updateId)}@${classNames.get(updateId)}`;
|
|
@@ -320,7 +266,7 @@ export function angular(options) {
|
|
|
320
266
|
}
|
|
321
267
|
return undefined;
|
|
322
268
|
},
|
|
323
|
-
async load(id
|
|
269
|
+
async load(id) {
|
|
324
270
|
// Map angular inline styles to the source text
|
|
325
271
|
if (isComponentStyleSheet(id)) {
|
|
326
272
|
const componentStyles = inlineComponentStyles?.get(getFilenameFromPath(id));
|
|
@@ -328,17 +274,6 @@ export function angular(options) {
|
|
|
328
274
|
return componentStyles;
|
|
329
275
|
}
|
|
330
276
|
}
|
|
331
|
-
if (pluginOptions.liveReload &&
|
|
332
|
-
options?.ssr &&
|
|
333
|
-
id.includes(ANGULAR_COMPONENT_PREFIX)) {
|
|
334
|
-
const requestUrl = new URL(id.slice(1), 'http://localhost');
|
|
335
|
-
const componentId = requestUrl.searchParams.get('c');
|
|
336
|
-
if (!componentId) {
|
|
337
|
-
return;
|
|
338
|
-
}
|
|
339
|
-
const result = await fileEmitter?.(resolve(process.cwd(), decodeURIComponent(componentId).split('@')[0]));
|
|
340
|
-
return result?.hmrUpdateCode || '';
|
|
341
|
-
}
|
|
342
277
|
return;
|
|
343
278
|
},
|
|
344
279
|
async transform(code, id) {
|
|
@@ -394,12 +329,17 @@ export function angular(options) {
|
|
|
394
329
|
* for test(Vitest)
|
|
395
330
|
*/
|
|
396
331
|
if (isTest) {
|
|
332
|
+
if (isVitestVscode && !initialCompilation) {
|
|
333
|
+
// Do full initial compilation
|
|
334
|
+
await performCompilation(resolvedConfig);
|
|
335
|
+
initialCompilation = true;
|
|
336
|
+
}
|
|
397
337
|
const tsMod = viteServer?.moduleGraph.getModuleById(id);
|
|
398
338
|
if (tsMod) {
|
|
399
339
|
const invalidated = tsMod.lastInvalidationTimestamp;
|
|
400
340
|
if (testWatchMode && invalidated) {
|
|
401
341
|
sourceFileCache.invalidate([id]);
|
|
402
|
-
await
|
|
342
|
+
await performCompilation(resolvedConfig, [id]);
|
|
403
343
|
}
|
|
404
344
|
}
|
|
405
345
|
}
|
|
@@ -414,7 +354,7 @@ export function angular(options) {
|
|
|
414
354
|
this.addWatchFile(absoluteFileUrl);
|
|
415
355
|
}
|
|
416
356
|
}
|
|
417
|
-
const typescriptResult =
|
|
357
|
+
const typescriptResult = fileEmitter(id);
|
|
418
358
|
if (typescriptResult?.warnings &&
|
|
419
359
|
typescriptResult?.warnings.length > 0) {
|
|
420
360
|
this.warn(`${typescriptResult.warnings.join('\n')}`);
|
|
@@ -435,25 +375,6 @@ export function angular(options) {
|
|
|
435
375
|
data = data.replace(`angular:jit:style:file;${styleFile}`, `${resolvedStyleUrl}?inline`);
|
|
436
376
|
});
|
|
437
377
|
}
|
|
438
|
-
if (jit) {
|
|
439
|
-
return {
|
|
440
|
-
code: data,
|
|
441
|
-
map: null,
|
|
442
|
-
};
|
|
443
|
-
}
|
|
444
|
-
if ((id.endsWith('.analog') ||
|
|
445
|
-
id.endsWith('.agx') ||
|
|
446
|
-
id.endsWith('.ag')) &&
|
|
447
|
-
pluginOptions.supportAnalogFormat &&
|
|
448
|
-
fileEmitter) {
|
|
449
|
-
sourceFileCache.invalidate([`${id}.ts`]);
|
|
450
|
-
const ngFileResult = await fileEmitter(`${id}.ts`);
|
|
451
|
-
data = ngFileResult?.content || '';
|
|
452
|
-
if (id.includes('.agx')) {
|
|
453
|
-
const metadata = await getFrontmatterMetadata(code, id, pluginOptions.markdownTemplateTransforms || []);
|
|
454
|
-
data += metadata;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
378
|
return {
|
|
458
379
|
code: data,
|
|
459
380
|
map: null,
|
|
@@ -461,10 +382,18 @@ export function angular(options) {
|
|
|
461
382
|
}
|
|
462
383
|
return undefined;
|
|
463
384
|
},
|
|
385
|
+
closeBundle() {
|
|
386
|
+
declarationFiles.forEach(({ declarationFileDir, declarationPath, data }) => {
|
|
387
|
+
mkdirSync(declarationFileDir, { recursive: true });
|
|
388
|
+
writeFileSync(declarationPath, data, 'utf-8');
|
|
389
|
+
});
|
|
390
|
+
},
|
|
464
391
|
};
|
|
465
392
|
}
|
|
466
393
|
return [
|
|
394
|
+
replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
467
395
|
angularPlugin(),
|
|
396
|
+
pluginOptions.liveReload && liveReloadPlugin({ classNames, fileEmitter }),
|
|
468
397
|
...(isTest && !isStackBlitz ? angularVitestPlugins() : []),
|
|
469
398
|
(jit &&
|
|
470
399
|
jitPlugin({
|
|
@@ -474,36 +403,12 @@ export function angular(options) {
|
|
|
474
403
|
supportedBrowsers: pluginOptions.supportedBrowsers,
|
|
475
404
|
jit,
|
|
476
405
|
}),
|
|
477
|
-
(isStorybook &&
|
|
406
|
+
(isStorybook &&
|
|
407
|
+
angularStorybookPlugin(pluginOptions.workspaceRoot)),
|
|
478
408
|
routerPlugin(),
|
|
479
409
|
pendingTasksPlugin(),
|
|
410
|
+
nxFolderPlugin(),
|
|
480
411
|
].filter(Boolean);
|
|
481
|
-
function findAnalogFiles(config) {
|
|
482
|
-
const analogConfig = pluginOptions.supportAnalogFormat;
|
|
483
|
-
if (!analogConfig) {
|
|
484
|
-
return [];
|
|
485
|
-
}
|
|
486
|
-
let extraGlobs = [];
|
|
487
|
-
if (typeof analogConfig === 'object') {
|
|
488
|
-
if (analogConfig.include) {
|
|
489
|
-
extraGlobs = analogConfig.include;
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
const fg = require('fast-glob');
|
|
493
|
-
const appRoot = normalizePath(resolve(pluginOptions.workspaceRoot, config.root || '.'));
|
|
494
|
-
const workspaceRoot = normalizePath(resolve(pluginOptions.workspaceRoot));
|
|
495
|
-
const globs = [
|
|
496
|
-
`${appRoot}/**/*.{analog,agx,ag}`,
|
|
497
|
-
...extraGlobs.map((glob) => `${workspaceRoot}${glob}.{analog,agx,ag}`),
|
|
498
|
-
...(pluginOptions.additionalContentDirs || [])?.map((glob) => `${workspaceRoot}${glob}/**/*.agx`),
|
|
499
|
-
...pluginOptions.include.map((glob) => `${workspaceRoot}${glob}`.replace(/\.ts$/, '.analog')),
|
|
500
|
-
];
|
|
501
|
-
return fg
|
|
502
|
-
.sync(globs, {
|
|
503
|
-
dot: true,
|
|
504
|
-
})
|
|
505
|
-
.map((file) => `${file}.ts`);
|
|
506
|
-
}
|
|
507
412
|
function findIncludes() {
|
|
508
413
|
const fg = require('fast-glob');
|
|
509
414
|
const workspaceRoot = normalizePath(resolve(pluginOptions.workspaceRoot));
|
|
@@ -514,11 +419,28 @@ export function angular(options) {
|
|
|
514
419
|
dot: true,
|
|
515
420
|
});
|
|
516
421
|
}
|
|
517
|
-
function
|
|
422
|
+
function getTsConfigPath(root, options, isProd, isTest, isLib) {
|
|
423
|
+
if (options.tsconfig && isAbsolute(options.tsconfig)) {
|
|
424
|
+
return options.tsconfig;
|
|
425
|
+
}
|
|
426
|
+
let tsconfigFilePath = './tsconfig.app.json';
|
|
427
|
+
if (isLib) {
|
|
428
|
+
tsconfigFilePath = isProd
|
|
429
|
+
? './tsconfig.lib.prod.json'
|
|
430
|
+
: './tsconfig.lib.json';
|
|
431
|
+
}
|
|
432
|
+
if (isTest) {
|
|
433
|
+
tsconfigFilePath = './tsconfig.spec.json';
|
|
434
|
+
}
|
|
435
|
+
if (options.tsconfig) {
|
|
436
|
+
tsconfigFilePath = options.tsconfig;
|
|
437
|
+
}
|
|
438
|
+
return resolve(root, tsconfigFilePath);
|
|
439
|
+
}
|
|
440
|
+
async function performCompilation(config, ids) {
|
|
518
441
|
const isProd = config.mode === 'production';
|
|
519
|
-
const analogFiles = findAnalogFiles(config);
|
|
520
442
|
const includeFiles = findIncludes();
|
|
521
|
-
|
|
443
|
+
let { options: tsCompilerOptions, rootNames } = compilerCli.readConfiguration(pluginOptions.tsconfig, {
|
|
522
444
|
suppressOutputPathCheck: true,
|
|
523
445
|
outDir: undefined,
|
|
524
446
|
sourceMap: false,
|
|
@@ -535,12 +457,6 @@ export function angular(options) {
|
|
|
535
457
|
supportTestBed: false,
|
|
536
458
|
supportJitMode: false,
|
|
537
459
|
});
|
|
538
|
-
if (pluginOptions.supportAnalogFormat) {
|
|
539
|
-
// Experimental Local Compilation is necessary
|
|
540
|
-
// for the Angular compiler to work with
|
|
541
|
-
// AOT and virtually compiled .analog files.
|
|
542
|
-
tsCompilerOptions.compilationMode = 'experimental-local';
|
|
543
|
-
}
|
|
544
460
|
if (pluginOptions.liveReload && watchMode) {
|
|
545
461
|
tsCompilerOptions['_enableHmr'] = true;
|
|
546
462
|
tsCompilerOptions['externalRuntimeStyles'] = true;
|
|
@@ -553,11 +469,17 @@ export function angular(options) {
|
|
|
553
469
|
tsCompilerOptions['supportTestBed'] = true;
|
|
554
470
|
tsCompilerOptions['supportJitMode'] = true;
|
|
555
471
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
472
|
+
if (!isTest && config.build?.lib) {
|
|
473
|
+
tsCompilerOptions['declaration'] = true;
|
|
474
|
+
tsCompilerOptions['declarationMap'] = watchMode;
|
|
475
|
+
tsCompilerOptions['inlineSources'] = true;
|
|
476
|
+
}
|
|
477
|
+
const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
|
|
478
|
+
rootNames = rootNames.concat(includeFiles, replacements);
|
|
479
|
+
const ts = require('typescript');
|
|
480
|
+
const host = ts.createIncrementalCompilerHost(tsCompilerOptions);
|
|
560
481
|
if (!jit) {
|
|
482
|
+
const styleTransform = (code, filename) => preprocessCSS(code, filename, config);
|
|
561
483
|
inlineComponentStyles = tsCompilerOptions['externalRuntimeStyles']
|
|
562
484
|
? new Map()
|
|
563
485
|
: undefined;
|
|
@@ -566,59 +488,119 @@ export function angular(options) {
|
|
|
566
488
|
: undefined;
|
|
567
489
|
augmentHostWithResources(host, styleTransform, {
|
|
568
490
|
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
569
|
-
supportAnalogFormat: pluginOptions.supportAnalogFormat,
|
|
570
491
|
isProd,
|
|
571
|
-
markdownTemplateTransforms: pluginOptions.markdownTemplateTransforms,
|
|
572
492
|
inlineComponentStyles,
|
|
573
493
|
externalComponentStyles,
|
|
574
494
|
});
|
|
575
495
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
*/
|
|
582
|
-
async function buildAndAnalyze() {
|
|
496
|
+
/**
|
|
497
|
+
* Creates a new NgtscProgram to analyze/re-analyze
|
|
498
|
+
* the source files and create a file emitter.
|
|
499
|
+
* This is shared between an initial build and a hot update.
|
|
500
|
+
*/
|
|
583
501
|
let builder;
|
|
584
502
|
let typeScriptProgram;
|
|
585
503
|
let angularCompiler;
|
|
586
504
|
if (!jit) {
|
|
587
505
|
// Create the Angular specific program that contains the Angular compiler
|
|
588
|
-
const angularProgram = new compilerCli.NgtscProgram(rootNames,
|
|
506
|
+
const angularProgram = new compilerCli.NgtscProgram(rootNames, tsCompilerOptions, host, nextProgram);
|
|
589
507
|
angularCompiler = angularProgram.compiler;
|
|
590
508
|
typeScriptProgram = angularProgram.getTsProgram();
|
|
591
509
|
augmentProgramWithVersioning(typeScriptProgram);
|
|
592
|
-
builder = builderProgram
|
|
593
|
-
ts.createEmitAndSemanticDiagnosticsBuilderProgram(typeScriptProgram, host, builderProgram);
|
|
510
|
+
builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(typeScriptProgram, host, builderProgram);
|
|
594
511
|
await angularCompiler.analyzeAsync();
|
|
595
512
|
nextProgram = angularProgram;
|
|
513
|
+
builderProgram =
|
|
514
|
+
builder;
|
|
596
515
|
}
|
|
597
516
|
else {
|
|
598
|
-
builder =
|
|
599
|
-
ts.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, compilerOptions, host, nextProgram);
|
|
517
|
+
builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, tsCompilerOptions, host, nextProgram);
|
|
600
518
|
typeScriptProgram = builder.getProgram();
|
|
601
|
-
nextProgram = builderProgram;
|
|
602
519
|
}
|
|
603
520
|
if (!watchMode) {
|
|
604
521
|
// When not in watch mode, the startup cost of the incremental analysis can be avoided by
|
|
605
522
|
// using an abstract builder that only wraps a TypeScript program.
|
|
606
523
|
builder = ts.createAbstractBuilder(typeScriptProgram, host);
|
|
607
524
|
}
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
525
|
+
const beforeTransformers = jit
|
|
526
|
+
? [
|
|
527
|
+
compilerCli.constructorParametersDownlevelTransform(builder.getProgram()),
|
|
528
|
+
createJitResourceTransformer(() => builder.getProgram().getTypeChecker()),
|
|
529
|
+
]
|
|
530
|
+
: [];
|
|
531
|
+
const transformers = mergeTransformers({ before: beforeTransformers }, jit ? {} : angularCompiler.prepareEmit().transformers);
|
|
532
|
+
const fileMetadata = getFileMetadata(builder, angularCompiler, pluginOptions.liveReload, pluginOptions.disableTypeChecking);
|
|
533
|
+
const writeFileCallback = (_filename, content, _a, _b, sourceFiles) => {
|
|
534
|
+
if (!sourceFiles?.length) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const filename = normalizePath(sourceFiles[0].fileName);
|
|
538
|
+
if (filename.includes('ngtypecheck.ts') || filename.includes('.d.')) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const metadata = watchMode ? fileMetadata(filename) : {};
|
|
542
|
+
outputFiles.set(filename, {
|
|
543
|
+
content,
|
|
544
|
+
dependencies: [],
|
|
545
|
+
errors: metadata.errors,
|
|
546
|
+
warnings: metadata.warnings,
|
|
547
|
+
hmrUpdateCode: metadata.hmrUpdateCode,
|
|
548
|
+
hmrEligible: metadata.hmrEligible,
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
const writeOutputFile = (id) => {
|
|
552
|
+
const sourceFile = builder.getSourceFile(id);
|
|
553
|
+
if (!sourceFile) {
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
let content = '';
|
|
557
|
+
builder.emit(sourceFile, (filename, data) => {
|
|
558
|
+
if (/\.[cm]?js$/.test(filename)) {
|
|
559
|
+
content = data;
|
|
560
|
+
}
|
|
561
|
+
if (!watchMode &&
|
|
562
|
+
!isTest &&
|
|
563
|
+
/\.d\.ts/.test(filename) &&
|
|
564
|
+
!filename.includes('.ngtypecheck.')) {
|
|
565
|
+
// output to library root instead /src
|
|
566
|
+
const declarationPath = resolve(config.root, config.build.outDir, relative(config.root, filename)).replace('/src/', '/');
|
|
567
|
+
const declarationFileDir = declarationPath
|
|
568
|
+
.replace(basename(filename), '')
|
|
569
|
+
.replace('/src/', '/');
|
|
570
|
+
declarationFiles.push({
|
|
571
|
+
declarationFileDir,
|
|
572
|
+
declarationPath,
|
|
573
|
+
data,
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}, undefined /* cancellationToken */, undefined /* emitOnlyDtsFiles */, transformers);
|
|
577
|
+
writeFileCallback(id, content, false, undefined, [sourceFile]);
|
|
578
|
+
};
|
|
579
|
+
if (watchMode) {
|
|
580
|
+
if (ids && ids.length > 0) {
|
|
581
|
+
ids.forEach((id) => writeOutputFile(id));
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
/**
|
|
585
|
+
* Only block the server from starting up
|
|
586
|
+
* during testing.
|
|
587
|
+
*/
|
|
588
|
+
if (isTest) {
|
|
589
|
+
// TypeScript will loop until there are no more affected files in the program
|
|
590
|
+
while (builder.emitNextAffectedFile(writeFileCallback, undefined, undefined, transformers)) {
|
|
591
|
+
/* empty */
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (!isTest) {
|
|
597
|
+
/**
|
|
598
|
+
* Perf: Output files on demand so the dev server
|
|
599
|
+
* isn't blocked when emitting files.
|
|
600
|
+
*/
|
|
601
|
+
outputFile = writeOutputFile;
|
|
602
|
+
}
|
|
603
|
+
return { host };
|
|
622
604
|
}
|
|
623
605
|
}
|
|
624
606
|
function sendHMRComponentUpdate(server, id) {
|
|
@@ -628,15 +610,12 @@ function sendHMRComponentUpdate(server, id) {
|
|
|
628
610
|
});
|
|
629
611
|
classNames.delete(id);
|
|
630
612
|
}
|
|
631
|
-
export function
|
|
632
|
-
|
|
613
|
+
export function getFileMetadata(program, angularCompiler, liveReload, disableTypeChecking) {
|
|
614
|
+
const ts = require('typescript');
|
|
615
|
+
return (file) => {
|
|
633
616
|
const sourceFile = program.getSourceFile(file);
|
|
634
617
|
if (!sourceFile) {
|
|
635
|
-
return
|
|
636
|
-
}
|
|
637
|
-
if (stale) {
|
|
638
|
-
const hmrEligible = !!analyzeFileUpdates(stale, sourceFile, angularCompiler);
|
|
639
|
-
return { dependencies: [], hmrEligible };
|
|
618
|
+
return {};
|
|
640
619
|
}
|
|
641
620
|
const diagnostics = getDiagnosticsForSourceFile(sourceFile, !!disableTypeChecking, program, angularCompiler);
|
|
642
621
|
const errors = diagnostics
|
|
@@ -648,22 +627,19 @@ export function createFileEmitter(program, transformers = {}, onAfterEmit, angul
|
|
|
648
627
|
.filter((d) => d.category === ts.DiagnosticCategory?.Warning)
|
|
649
628
|
.map((d) => d.messageText);
|
|
650
629
|
let hmrUpdateCode = undefined;
|
|
630
|
+
let hmrEligible = false;
|
|
651
631
|
if (liveReload) {
|
|
652
632
|
for (const node of sourceFile.statements) {
|
|
653
633
|
if (ts.isClassDeclaration(node) && node.name != null) {
|
|
654
634
|
hmrUpdateCode = angularCompiler?.emitHmrUpdateModule(node);
|
|
655
|
-
!!hmrUpdateCode
|
|
635
|
+
if (!!hmrUpdateCode) {
|
|
636
|
+
classNames.set(file, node.name.getText());
|
|
637
|
+
hmrEligible = true;
|
|
638
|
+
}
|
|
656
639
|
}
|
|
657
640
|
}
|
|
658
641
|
}
|
|
659
|
-
|
|
660
|
-
program.emit(sourceFile, (filename, data) => {
|
|
661
|
-
if (/\.[cm]?js$/.test(filename)) {
|
|
662
|
-
content = data;
|
|
663
|
-
}
|
|
664
|
-
}, undefined /* cancellationToken */, undefined /* emitOnlyDtsFiles */, transformers);
|
|
665
|
-
onAfterEmit?.(sourceFile);
|
|
666
|
-
return { content, dependencies: [], errors, warnings, hmrUpdateCode };
|
|
642
|
+
return { errors, warnings, hmrUpdateCode, hmrEligible };
|
|
667
643
|
};
|
|
668
644
|
}
|
|
669
645
|
function getDiagnosticsForSourceFile(sourceFile, disableTypeChecking, program, angularCompiler) {
|