@analogjs/vite-plugin-angular 2.0.0-alpha.9 → 2.0.0-beta.10
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 +14 -24
- package/src/lib/angular-vite-plugin.js +224 -220
- 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,30 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { basename, dirname, isAbsolute, join, relative, resolve, } from 'node:path';
|
|
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';
|
|
6
5
|
import * as ngCompiler from '@angular/compiler';
|
|
6
|
+
import { defaultClientConditions, normalizePath, preprocessCSS, } from 'vite';
|
|
7
|
+
import { buildOptimizerPlugin } from './angular-build-optimizer-plugin.js';
|
|
8
|
+
import { jitPlugin } from './angular-jit-plugin.js';
|
|
7
9
|
import { createCompilerPlugin } from './compiler-plugin.js';
|
|
8
10
|
import { StyleUrlsResolver, TemplateUrlsResolver, } from './component-resolvers.js';
|
|
9
11
|
import { augmentHostWithCaching, augmentHostWithResources, augmentProgramWithVersioning, mergeTransformers, } from './host.js';
|
|
10
|
-
import { jitPlugin } from './angular-jit-plugin.js';
|
|
11
|
-
import { buildOptimizerPlugin } from './angular-build-optimizer-plugin.js';
|
|
12
|
-
import { createJitResourceTransformer, SourceFileCache, angularMajor, } from './utils/devkit.js';
|
|
13
|
-
import { angularVitestPlugins } from './angular-vitest-plugin.js';
|
|
14
12
|
import { angularStorybookPlugin } from './angular-storybook-plugin.js';
|
|
13
|
+
import { angularVitestPlugins } from './angular-vitest-plugin.js';
|
|
14
|
+
import { angularMajor, createJitResourceTransformer, SourceFileCache, } from './utils/devkit.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
|
-
import { routerPlugin } from './router-plugin.js';
|
|
19
16
|
import { pendingTasksPlugin } from './angular-pending-tasks.plugin.js';
|
|
20
|
-
import {
|
|
17
|
+
import { liveReloadPlugin } from './live-reload-plugin.js';
|
|
18
|
+
import { nxFolderPlugin } from './nx-folder-plugin.js';
|
|
19
|
+
import { replaceFiles, } from './plugins/file-replacements.plugin.js';
|
|
20
|
+
import { routerPlugin } from './router-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
|
-
|
|
36
|
-
(process.env['NODE_ENV'] === 'test'
|
|
37
|
-
? './tsconfig.spec.json'
|
|
38
|
-
: './tsconfig.app.json'),
|
|
34
|
+
tsconfigGetter: createTsConfigGetter(options?.tsconfig),
|
|
39
35
|
workspaceRoot: options?.workspaceRoot ?? process.cwd(),
|
|
40
36
|
inlineStylesExtension: options?.inlineStylesExtension ?? 'css',
|
|
41
37
|
advanced: {
|
|
@@ -46,24 +42,17 @@ 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
|
|
66
|
-
|
|
53
|
+
let resolvedTsConfigPath = '';
|
|
54
|
+
// Store config context needed for getTsConfigPath resolution
|
|
55
|
+
let tsConfigResolutionContext = null;
|
|
67
56
|
let nextProgram;
|
|
68
57
|
let builderProgram;
|
|
69
58
|
let watchMode = false;
|
|
@@ -72,6 +61,7 @@ export function angular(options) {
|
|
|
72
61
|
let externalComponentStyles;
|
|
73
62
|
const sourceFileCache = new SourceFileCache();
|
|
74
63
|
const isTest = process.env['NODE_ENV'] === 'test' || !!process.env['VITEST'];
|
|
64
|
+
const isVitestVscode = !!process.env['VITEST_VSCODE'];
|
|
75
65
|
const isStackBlitz = !!process.versions['webcontainer'];
|
|
76
66
|
const isAstroIntegration = process.env['ANALOG_ASTRO'] === 'true';
|
|
77
67
|
const isStorybook = process.env['npm_lifecycle_script']?.includes('storybook') ||
|
|
@@ -80,9 +70,16 @@ export function angular(options) {
|
|
|
80
70
|
process.env['ANALOG_STORYBOOK'] === 'true';
|
|
81
71
|
const jit = typeof pluginOptions?.jit !== 'undefined' ? pluginOptions.jit : isTest;
|
|
82
72
|
let viteServer;
|
|
83
|
-
let styleTransform;
|
|
84
73
|
const styleUrlsResolver = new StyleUrlsResolver();
|
|
85
74
|
const templateUrlsResolver = new TemplateUrlsResolver();
|
|
75
|
+
let outputFile;
|
|
76
|
+
const outputFiles = new Map();
|
|
77
|
+
const fileEmitter = (file) => {
|
|
78
|
+
outputFile?.(file);
|
|
79
|
+
return outputFiles.get(normalizePath(file));
|
|
80
|
+
};
|
|
81
|
+
let initialCompilation = false;
|
|
82
|
+
const declarationFiles = [];
|
|
86
83
|
function angularPlugin() {
|
|
87
84
|
let isProd = false;
|
|
88
85
|
if (angularMajor < 19 || isTest) {
|
|
@@ -90,21 +87,19 @@ export function angular(options) {
|
|
|
90
87
|
}
|
|
91
88
|
return {
|
|
92
89
|
name: '@analogjs/vite-plugin-angular',
|
|
93
|
-
async watchChange() {
|
|
94
|
-
if (isTest) {
|
|
95
|
-
await buildAndAnalyze();
|
|
96
|
-
}
|
|
97
|
-
},
|
|
98
90
|
async config(config, { command }) {
|
|
99
91
|
watchMode = command === 'serve';
|
|
100
92
|
isProd =
|
|
101
93
|
config.mode === 'production' ||
|
|
102
94
|
process.env['NODE_ENV'] === 'production';
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
95
|
+
// Store the config context for later resolution in configResolved
|
|
96
|
+
tsConfigResolutionContext = {
|
|
97
|
+
root: config.root || '.',
|
|
98
|
+
isProd,
|
|
99
|
+
isLib: !!config?.build?.lib,
|
|
100
|
+
};
|
|
101
|
+
// Do a preliminary resolution for esbuild plugin (before configResolved)
|
|
102
|
+
const preliminaryTsConfigPath = getTsConfigPath(tsConfigResolutionContext.root, pluginOptions.tsconfigGetter(), tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
|
|
108
103
|
return {
|
|
109
104
|
esbuild: config.esbuild ?? false,
|
|
110
105
|
optimizeDeps: {
|
|
@@ -113,7 +108,7 @@ export function angular(options) {
|
|
|
113
108
|
esbuildOptions: {
|
|
114
109
|
plugins: [
|
|
115
110
|
createCompilerPlugin({
|
|
116
|
-
tsconfig:
|
|
111
|
+
tsconfig: preliminaryTsConfigPath,
|
|
117
112
|
sourcemap: !isProd,
|
|
118
113
|
advancedOptimizations: isProd,
|
|
119
114
|
jit,
|
|
@@ -128,12 +123,20 @@ export function angular(options) {
|
|
|
128
123
|
},
|
|
129
124
|
},
|
|
130
125
|
resolve: {
|
|
131
|
-
conditions: [
|
|
126
|
+
conditions: [
|
|
127
|
+
'style',
|
|
128
|
+
...(config.resolve?.conditions || defaultClientConditions),
|
|
129
|
+
],
|
|
132
130
|
},
|
|
133
131
|
};
|
|
134
132
|
},
|
|
135
133
|
configResolved(config) {
|
|
136
134
|
resolvedConfig = config;
|
|
135
|
+
// resolve the tsconfig path after config is fully resolved
|
|
136
|
+
if (tsConfigResolutionContext) {
|
|
137
|
+
const tsconfigValue = pluginOptions.tsconfigGetter();
|
|
138
|
+
resolvedTsConfigPath = getTsConfigPath(tsConfigResolutionContext.root, tsconfigValue, tsConfigResolutionContext.isProd, isTest, tsConfigResolutionContext.isLib);
|
|
139
|
+
}
|
|
137
140
|
if (isTest) {
|
|
138
141
|
// set test watch mode
|
|
139
142
|
// - vite override from vitest-angular
|
|
@@ -149,76 +152,30 @@ export function angular(options) {
|
|
|
149
152
|
configureServer(server) {
|
|
150
153
|
viteServer = server;
|
|
151
154
|
server.watcher.on('add', async () => {
|
|
152
|
-
|
|
153
|
-
await buildAndAnalyze();
|
|
155
|
+
await performCompilation(resolvedConfig);
|
|
154
156
|
});
|
|
155
157
|
server.watcher.on('unlink', async () => {
|
|
156
|
-
|
|
157
|
-
await buildAndAnalyze();
|
|
158
|
+
await performCompilation(resolvedConfig);
|
|
158
159
|
});
|
|
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
160
|
},
|
|
194
161
|
async buildStart() {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
162
|
+
// Defer the first compilation in test mode
|
|
163
|
+
if (!isVitestVscode) {
|
|
164
|
+
const { host } = await performCompilation(resolvedConfig);
|
|
165
|
+
initialCompilation = true;
|
|
166
|
+
// Only store cache if in watch mode
|
|
167
|
+
if (watchMode) {
|
|
168
|
+
augmentHostWithCaching(host, sourceFileCache);
|
|
169
|
+
}
|
|
199
170
|
}
|
|
200
|
-
await buildAndAnalyze();
|
|
201
171
|
},
|
|
202
172
|
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
173
|
if (TS_EXT_REGEX.test(ctx.file)) {
|
|
211
174
|
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);
|
|
175
|
+
await performCompilation(resolvedConfig, [fileId]);
|
|
176
|
+
const result = fileEmitter(fileId);
|
|
220
177
|
if (pluginOptions.liveReload &&
|
|
221
|
-
|
|
178
|
+
result?.hmrEligible &&
|
|
222
179
|
classNames.get(fileId)) {
|
|
223
180
|
const relativeFileId = `${relative(process.cwd(), fileId)}@${classNames.get(fileId)}`;
|
|
224
181
|
sendHMRComponentUpdate(ctx.server, relativeFileId);
|
|
@@ -236,7 +193,8 @@ export function angular(options) {
|
|
|
236
193
|
* for an external resource (styles, html).
|
|
237
194
|
*/
|
|
238
195
|
const isDirect = ctx.modules.find((mod) => ctx.file === mod.file && mod.id?.includes('?direct'));
|
|
239
|
-
|
|
196
|
+
const isInline = ctx.modules.find((mod) => ctx.file === mod.file && mod.id?.includes('?inline'));
|
|
197
|
+
if (isDirect || isInline) {
|
|
240
198
|
if (pluginOptions.liveReload && isDirect?.id && isDirect.file) {
|
|
241
199
|
const isComponentStyle = isDirect.type === 'css' && isComponentStyleSheet(isDirect.id);
|
|
242
200
|
if (isComponentStyle) {
|
|
@@ -287,7 +245,10 @@ export function angular(options) {
|
|
|
287
245
|
}
|
|
288
246
|
});
|
|
289
247
|
});
|
|
290
|
-
await
|
|
248
|
+
await performCompilation(resolvedConfig, [
|
|
249
|
+
...mods.map((mod) => mod.id),
|
|
250
|
+
...updates,
|
|
251
|
+
]);
|
|
291
252
|
if (updates.length > 0) {
|
|
292
253
|
updates.forEach((updateId) => {
|
|
293
254
|
const impRelativeFileId = `${relative(process.cwd(), updateId)}@${classNames.get(updateId)}`;
|
|
@@ -320,7 +281,7 @@ export function angular(options) {
|
|
|
320
281
|
}
|
|
321
282
|
return undefined;
|
|
322
283
|
},
|
|
323
|
-
async load(id
|
|
284
|
+
async load(id) {
|
|
324
285
|
// Map angular inline styles to the source text
|
|
325
286
|
if (isComponentStyleSheet(id)) {
|
|
326
287
|
const componentStyles = inlineComponentStyles?.get(getFilenameFromPath(id));
|
|
@@ -328,17 +289,6 @@ export function angular(options) {
|
|
|
328
289
|
return componentStyles;
|
|
329
290
|
}
|
|
330
291
|
}
|
|
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
292
|
return;
|
|
343
293
|
},
|
|
344
294
|
async transform(code, id) {
|
|
@@ -394,12 +344,17 @@ export function angular(options) {
|
|
|
394
344
|
* for test(Vitest)
|
|
395
345
|
*/
|
|
396
346
|
if (isTest) {
|
|
347
|
+
if (isVitestVscode && !initialCompilation) {
|
|
348
|
+
// Do full initial compilation
|
|
349
|
+
await performCompilation(resolvedConfig);
|
|
350
|
+
initialCompilation = true;
|
|
351
|
+
}
|
|
397
352
|
const tsMod = viteServer?.moduleGraph.getModuleById(id);
|
|
398
353
|
if (tsMod) {
|
|
399
354
|
const invalidated = tsMod.lastInvalidationTimestamp;
|
|
400
355
|
if (testWatchMode && invalidated) {
|
|
401
356
|
sourceFileCache.invalidate([id]);
|
|
402
|
-
await
|
|
357
|
+
await performCompilation(resolvedConfig, [id]);
|
|
403
358
|
}
|
|
404
359
|
}
|
|
405
360
|
}
|
|
@@ -414,7 +369,7 @@ export function angular(options) {
|
|
|
414
369
|
this.addWatchFile(absoluteFileUrl);
|
|
415
370
|
}
|
|
416
371
|
}
|
|
417
|
-
const typescriptResult =
|
|
372
|
+
const typescriptResult = fileEmitter(id);
|
|
418
373
|
if (typescriptResult?.warnings &&
|
|
419
374
|
typescriptResult?.warnings.length > 0) {
|
|
420
375
|
this.warn(`${typescriptResult.warnings.join('\n')}`);
|
|
@@ -435,25 +390,6 @@ export function angular(options) {
|
|
|
435
390
|
data = data.replace(`angular:jit:style:file;${styleFile}`, `${resolvedStyleUrl}?inline`);
|
|
436
391
|
});
|
|
437
392
|
}
|
|
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
393
|
return {
|
|
458
394
|
code: data,
|
|
459
395
|
map: null,
|
|
@@ -461,10 +397,18 @@ export function angular(options) {
|
|
|
461
397
|
}
|
|
462
398
|
return undefined;
|
|
463
399
|
},
|
|
400
|
+
closeBundle() {
|
|
401
|
+
declarationFiles.forEach(({ declarationFileDir, declarationPath, data }) => {
|
|
402
|
+
mkdirSync(declarationFileDir, { recursive: true });
|
|
403
|
+
writeFileSync(declarationPath, data, 'utf-8');
|
|
404
|
+
});
|
|
405
|
+
},
|
|
464
406
|
};
|
|
465
407
|
}
|
|
466
408
|
return [
|
|
409
|
+
replaceFiles(pluginOptions.fileReplacements, pluginOptions.workspaceRoot),
|
|
467
410
|
angularPlugin(),
|
|
411
|
+
pluginOptions.liveReload && liveReloadPlugin({ classNames, fileEmitter }),
|
|
468
412
|
...(isTest && !isStackBlitz ? angularVitestPlugins() : []),
|
|
469
413
|
(jit &&
|
|
470
414
|
jitPlugin({
|
|
@@ -474,36 +418,12 @@ export function angular(options) {
|
|
|
474
418
|
supportedBrowsers: pluginOptions.supportedBrowsers,
|
|
475
419
|
jit,
|
|
476
420
|
}),
|
|
477
|
-
(isStorybook &&
|
|
421
|
+
(isStorybook &&
|
|
422
|
+
angularStorybookPlugin(pluginOptions.workspaceRoot)),
|
|
478
423
|
routerPlugin(),
|
|
479
424
|
pendingTasksPlugin(),
|
|
425
|
+
nxFolderPlugin(),
|
|
480
426
|
].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
427
|
function findIncludes() {
|
|
508
428
|
const fg = require('fast-glob');
|
|
509
429
|
const workspaceRoot = normalizePath(resolve(pluginOptions.workspaceRoot));
|
|
@@ -514,11 +434,41 @@ export function angular(options) {
|
|
|
514
434
|
dot: true,
|
|
515
435
|
});
|
|
516
436
|
}
|
|
517
|
-
function
|
|
437
|
+
function createTsConfigGetter(tsconfigOrGetter) {
|
|
438
|
+
if (typeof tsconfigOrGetter === 'function') {
|
|
439
|
+
return tsconfigOrGetter;
|
|
440
|
+
}
|
|
441
|
+
return () => tsconfigOrGetter || '';
|
|
442
|
+
}
|
|
443
|
+
function getTsConfigPath(root, tsconfig, isProd, isTest, isLib) {
|
|
444
|
+
if (tsconfig && isAbsolute(tsconfig)) {
|
|
445
|
+
if (!existsSync(tsconfig)) {
|
|
446
|
+
console.error(`[@analogjs/vite-plugin-angular]: Unable to resolve tsconfig at ${tsconfig}. This causes compilation issues. Check the path or set the "tsconfig" property with an absolute path.`);
|
|
447
|
+
}
|
|
448
|
+
return tsconfig;
|
|
449
|
+
}
|
|
450
|
+
let tsconfigFilePath = './tsconfig.app.json';
|
|
451
|
+
if (isLib) {
|
|
452
|
+
tsconfigFilePath = isProd
|
|
453
|
+
? './tsconfig.lib.prod.json'
|
|
454
|
+
: './tsconfig.lib.json';
|
|
455
|
+
}
|
|
456
|
+
if (isTest) {
|
|
457
|
+
tsconfigFilePath = './tsconfig.spec.json';
|
|
458
|
+
}
|
|
459
|
+
if (tsconfig) {
|
|
460
|
+
tsconfigFilePath = tsconfig;
|
|
461
|
+
}
|
|
462
|
+
const resolvedPath = resolve(root, tsconfigFilePath);
|
|
463
|
+
if (!existsSync(resolvedPath)) {
|
|
464
|
+
console.error(`[@analogjs/vite-plugin-angular]: Unable to resolve tsconfig at ${resolvedPath}. This causes compilation issues. Check the path or set the "tsconfig" property with an absolute path.`);
|
|
465
|
+
}
|
|
466
|
+
return resolvedPath;
|
|
467
|
+
}
|
|
468
|
+
async function performCompilation(config, ids) {
|
|
518
469
|
const isProd = config.mode === 'production';
|
|
519
|
-
const analogFiles = findAnalogFiles(config);
|
|
520
470
|
const includeFiles = findIncludes();
|
|
521
|
-
|
|
471
|
+
let { options: tsCompilerOptions, rootNames } = compilerCli.readConfiguration(resolvedTsConfigPath, {
|
|
522
472
|
suppressOutputPathCheck: true,
|
|
523
473
|
outDir: undefined,
|
|
524
474
|
sourceMap: false,
|
|
@@ -535,12 +485,6 @@ export function angular(options) {
|
|
|
535
485
|
supportTestBed: false,
|
|
536
486
|
supportJitMode: false,
|
|
537
487
|
});
|
|
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
488
|
if (pluginOptions.liveReload && watchMode) {
|
|
545
489
|
tsCompilerOptions['_enableHmr'] = true;
|
|
546
490
|
tsCompilerOptions['externalRuntimeStyles'] = true;
|
|
@@ -553,11 +497,17 @@ export function angular(options) {
|
|
|
553
497
|
tsCompilerOptions['supportTestBed'] = true;
|
|
554
498
|
tsCompilerOptions['supportJitMode'] = true;
|
|
555
499
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
500
|
+
if (!isTest && config.build?.lib) {
|
|
501
|
+
tsCompilerOptions['declaration'] = true;
|
|
502
|
+
tsCompilerOptions['declarationMap'] = watchMode;
|
|
503
|
+
tsCompilerOptions['inlineSources'] = true;
|
|
504
|
+
}
|
|
505
|
+
const replacements = pluginOptions.fileReplacements.map((rp) => join(pluginOptions.workspaceRoot, rp.ssr || rp.with));
|
|
506
|
+
rootNames = rootNames.concat(includeFiles, replacements);
|
|
507
|
+
const ts = require('typescript');
|
|
508
|
+
const host = ts.createIncrementalCompilerHost(tsCompilerOptions);
|
|
560
509
|
if (!jit) {
|
|
510
|
+
const styleTransform = (code, filename) => preprocessCSS(code, filename, config);
|
|
561
511
|
inlineComponentStyles = tsCompilerOptions['externalRuntimeStyles']
|
|
562
512
|
? new Map()
|
|
563
513
|
: undefined;
|
|
@@ -566,59 +516,119 @@ export function angular(options) {
|
|
|
566
516
|
: undefined;
|
|
567
517
|
augmentHostWithResources(host, styleTransform, {
|
|
568
518
|
inlineStylesExtension: pluginOptions.inlineStylesExtension,
|
|
569
|
-
supportAnalogFormat: pluginOptions.supportAnalogFormat,
|
|
570
519
|
isProd,
|
|
571
|
-
markdownTemplateTransforms: pluginOptions.markdownTemplateTransforms,
|
|
572
520
|
inlineComponentStyles,
|
|
573
521
|
externalComponentStyles,
|
|
574
522
|
});
|
|
575
523
|
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
*/
|
|
582
|
-
async function buildAndAnalyze() {
|
|
524
|
+
/**
|
|
525
|
+
* Creates a new NgtscProgram to analyze/re-analyze
|
|
526
|
+
* the source files and create a file emitter.
|
|
527
|
+
* This is shared between an initial build and a hot update.
|
|
528
|
+
*/
|
|
583
529
|
let builder;
|
|
584
530
|
let typeScriptProgram;
|
|
585
531
|
let angularCompiler;
|
|
586
532
|
if (!jit) {
|
|
587
533
|
// Create the Angular specific program that contains the Angular compiler
|
|
588
|
-
const angularProgram = new compilerCli.NgtscProgram(rootNames,
|
|
534
|
+
const angularProgram = new compilerCli.NgtscProgram(rootNames, tsCompilerOptions, host, nextProgram);
|
|
589
535
|
angularCompiler = angularProgram.compiler;
|
|
590
536
|
typeScriptProgram = angularProgram.getTsProgram();
|
|
591
537
|
augmentProgramWithVersioning(typeScriptProgram);
|
|
592
|
-
builder = builderProgram
|
|
593
|
-
ts.createEmitAndSemanticDiagnosticsBuilderProgram(typeScriptProgram, host, builderProgram);
|
|
538
|
+
builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(typeScriptProgram, host, builderProgram);
|
|
594
539
|
await angularCompiler.analyzeAsync();
|
|
595
540
|
nextProgram = angularProgram;
|
|
541
|
+
builderProgram =
|
|
542
|
+
builder;
|
|
596
543
|
}
|
|
597
544
|
else {
|
|
598
|
-
builder =
|
|
599
|
-
ts.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, compilerOptions, host, nextProgram);
|
|
545
|
+
builder = ts.createEmitAndSemanticDiagnosticsBuilderProgram(rootNames, tsCompilerOptions, host, nextProgram);
|
|
600
546
|
typeScriptProgram = builder.getProgram();
|
|
601
|
-
nextProgram = builderProgram;
|
|
602
547
|
}
|
|
603
548
|
if (!watchMode) {
|
|
604
549
|
// When not in watch mode, the startup cost of the incremental analysis can be avoided by
|
|
605
550
|
// using an abstract builder that only wraps a TypeScript program.
|
|
606
551
|
builder = ts.createAbstractBuilder(typeScriptProgram, host);
|
|
607
552
|
}
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
553
|
+
const beforeTransformers = jit
|
|
554
|
+
? [
|
|
555
|
+
compilerCli.constructorParametersDownlevelTransform(builder.getProgram()),
|
|
556
|
+
createJitResourceTransformer(() => builder.getProgram().getTypeChecker()),
|
|
557
|
+
]
|
|
558
|
+
: [];
|
|
559
|
+
const transformers = mergeTransformers({ before: beforeTransformers }, jit ? {} : angularCompiler.prepareEmit().transformers);
|
|
560
|
+
const fileMetadata = getFileMetadata(builder, angularCompiler, pluginOptions.liveReload, pluginOptions.disableTypeChecking);
|
|
561
|
+
const writeFileCallback = (_filename, content, _a, _b, sourceFiles) => {
|
|
562
|
+
if (!sourceFiles?.length) {
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const filename = normalizePath(sourceFiles[0].fileName);
|
|
566
|
+
if (filename.includes('ngtypecheck.ts') || filename.includes('.d.')) {
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
const metadata = watchMode ? fileMetadata(filename) : {};
|
|
570
|
+
outputFiles.set(filename, {
|
|
571
|
+
content,
|
|
572
|
+
dependencies: [],
|
|
573
|
+
errors: metadata.errors,
|
|
574
|
+
warnings: metadata.warnings,
|
|
575
|
+
hmrUpdateCode: metadata.hmrUpdateCode,
|
|
576
|
+
hmrEligible: metadata.hmrEligible,
|
|
577
|
+
});
|
|
578
|
+
};
|
|
579
|
+
const writeOutputFile = (id) => {
|
|
580
|
+
const sourceFile = builder.getSourceFile(id);
|
|
581
|
+
if (!sourceFile) {
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
let content = '';
|
|
585
|
+
builder.emit(sourceFile, (filename, data) => {
|
|
586
|
+
if (/\.[cm]?js$/.test(filename)) {
|
|
587
|
+
content = data;
|
|
588
|
+
}
|
|
589
|
+
if (!watchMode &&
|
|
590
|
+
!isTest &&
|
|
591
|
+
/\.d\.ts/.test(filename) &&
|
|
592
|
+
!filename.includes('.ngtypecheck.')) {
|
|
593
|
+
// output to library root instead /src
|
|
594
|
+
const declarationPath = resolve(config.root, config.build.outDir, relative(config.root, filename)).replace('/src/', '/');
|
|
595
|
+
const declarationFileDir = declarationPath
|
|
596
|
+
.replace(basename(filename), '')
|
|
597
|
+
.replace('/src/', '/');
|
|
598
|
+
declarationFiles.push({
|
|
599
|
+
declarationFileDir,
|
|
600
|
+
declarationPath,
|
|
601
|
+
data,
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
}, undefined /* cancellationToken */, undefined /* emitOnlyDtsFiles */, transformers);
|
|
605
|
+
writeFileCallback(id, content, false, undefined, [sourceFile]);
|
|
606
|
+
};
|
|
607
|
+
if (watchMode) {
|
|
608
|
+
if (ids && ids.length > 0) {
|
|
609
|
+
ids.forEach((id) => writeOutputFile(id));
|
|
610
|
+
}
|
|
611
|
+
else {
|
|
612
|
+
/**
|
|
613
|
+
* Only block the server from starting up
|
|
614
|
+
* during testing.
|
|
615
|
+
*/
|
|
616
|
+
if (isTest) {
|
|
617
|
+
// TypeScript will loop until there are no more affected files in the program
|
|
618
|
+
while (builder.emitNextAffectedFile(writeFileCallback, undefined, undefined, transformers)) {
|
|
619
|
+
/* empty */
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
if (!isTest) {
|
|
625
|
+
/**
|
|
626
|
+
* Perf: Output files on demand so the dev server
|
|
627
|
+
* isn't blocked when emitting files.
|
|
628
|
+
*/
|
|
629
|
+
outputFile = writeOutputFile;
|
|
630
|
+
}
|
|
631
|
+
return { host };
|
|
622
632
|
}
|
|
623
633
|
}
|
|
624
634
|
function sendHMRComponentUpdate(server, id) {
|
|
@@ -628,15 +638,12 @@ function sendHMRComponentUpdate(server, id) {
|
|
|
628
638
|
});
|
|
629
639
|
classNames.delete(id);
|
|
630
640
|
}
|
|
631
|
-
export function
|
|
632
|
-
|
|
641
|
+
export function getFileMetadata(program, angularCompiler, liveReload, disableTypeChecking) {
|
|
642
|
+
const ts = require('typescript');
|
|
643
|
+
return (file) => {
|
|
633
644
|
const sourceFile = program.getSourceFile(file);
|
|
634
645
|
if (!sourceFile) {
|
|
635
|
-
return
|
|
636
|
-
}
|
|
637
|
-
if (stale) {
|
|
638
|
-
const hmrEligible = !!analyzeFileUpdates(stale, sourceFile, angularCompiler);
|
|
639
|
-
return { dependencies: [], hmrEligible };
|
|
646
|
+
return {};
|
|
640
647
|
}
|
|
641
648
|
const diagnostics = getDiagnosticsForSourceFile(sourceFile, !!disableTypeChecking, program, angularCompiler);
|
|
642
649
|
const errors = diagnostics
|
|
@@ -648,22 +655,19 @@ export function createFileEmitter(program, transformers = {}, onAfterEmit, angul
|
|
|
648
655
|
.filter((d) => d.category === ts.DiagnosticCategory?.Warning)
|
|
649
656
|
.map((d) => d.messageText);
|
|
650
657
|
let hmrUpdateCode = undefined;
|
|
658
|
+
let hmrEligible = false;
|
|
651
659
|
if (liveReload) {
|
|
652
660
|
for (const node of sourceFile.statements) {
|
|
653
661
|
if (ts.isClassDeclaration(node) && node.name != null) {
|
|
654
662
|
hmrUpdateCode = angularCompiler?.emitHmrUpdateModule(node);
|
|
655
|
-
!!hmrUpdateCode
|
|
663
|
+
if (!!hmrUpdateCode) {
|
|
664
|
+
classNames.set(file, node.name.getText());
|
|
665
|
+
hmrEligible = true;
|
|
666
|
+
}
|
|
656
667
|
}
|
|
657
668
|
}
|
|
658
669
|
}
|
|
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 };
|
|
670
|
+
return { errors, warnings, hmrUpdateCode, hmrEligible };
|
|
667
671
|
};
|
|
668
672
|
}
|
|
669
673
|
function getDiagnosticsForSourceFile(sourceFile, disableTypeChecking, program, angularCompiler) {
|