@angular-devkit/build-angular 19.0.0-rc.0 → 19.0.0-rc.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 +14 -14
- package/src/builders/dev-server/builder.js +4 -0
- package/src/builders/dev-server/options.d.ts +1 -1
- package/src/builders/dev-server/options.js +1 -1
- package/src/builders/dev-server/schema.json +1 -2
- package/src/builders/karma/application_builder.js +121 -31
- package/src/utils/normalize-cache.js +1 -1
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "19.0.0-rc.
|
|
3
|
+
"version": "19.0.0-rc.2",
|
|
4
4
|
"description": "Angular Webpack Build Facade",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"typings": "src/index.d.ts",
|
|
7
7
|
"builders": "builders.json",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@ampproject/remapping": "2.3.0",
|
|
10
|
-
"@angular-devkit/architect": "0.1900.0-rc.
|
|
11
|
-
"@angular-devkit/build-webpack": "0.1900.0-rc.
|
|
12
|
-
"@angular-devkit/core": "19.0.0-rc.
|
|
13
|
-
"@angular/build": "19.0.0-rc.
|
|
10
|
+
"@angular-devkit/architect": "0.1900.0-rc.2",
|
|
11
|
+
"@angular-devkit/build-webpack": "0.1900.0-rc.2",
|
|
12
|
+
"@angular-devkit/core": "19.0.0-rc.2",
|
|
13
|
+
"@angular/build": "19.0.0-rc.2",
|
|
14
14
|
"@babel/core": "7.26.0",
|
|
15
|
-
"@babel/generator": "7.26.
|
|
15
|
+
"@babel/generator": "7.26.2",
|
|
16
16
|
"@babel/helper-annotate-as-pure": "7.25.9",
|
|
17
17
|
"@babel/helper-split-export-declaration": "7.24.7",
|
|
18
18
|
"@babel/plugin-transform-async-generator-functions": "7.25.9",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@babel/preset-env": "7.26.0",
|
|
22
22
|
"@babel/runtime": "7.26.0",
|
|
23
23
|
"@discoveryjs/json-ext": "0.6.3",
|
|
24
|
-
"@ngtools/webpack": "19.0.0-rc.
|
|
24
|
+
"@ngtools/webpack": "19.0.0-rc.2",
|
|
25
25
|
"@vitejs/plugin-basic-ssl": "1.1.0",
|
|
26
26
|
"ansi-colors": "4.1.3",
|
|
27
27
|
"autoprefixer": "10.4.20",
|
|
@@ -39,24 +39,24 @@
|
|
|
39
39
|
"less-loader": "12.2.0",
|
|
40
40
|
"license-webpack-plugin": "4.0.2",
|
|
41
41
|
"loader-utils": "3.3.1",
|
|
42
|
-
"mini-css-extract-plugin": "2.9.
|
|
42
|
+
"mini-css-extract-plugin": "2.9.2",
|
|
43
43
|
"open": "10.1.0",
|
|
44
44
|
"ora": "5.4.1",
|
|
45
45
|
"picomatch": "4.0.2",
|
|
46
46
|
"piscina": "4.7.0",
|
|
47
|
-
"postcss": "8.4.
|
|
47
|
+
"postcss": "8.4.49",
|
|
48
48
|
"postcss-loader": "8.1.1",
|
|
49
49
|
"resolve-url-loader": "5.0.0",
|
|
50
50
|
"rxjs": "7.8.1",
|
|
51
|
-
"sass": "1.80.
|
|
52
|
-
"sass-loader": "16.0.
|
|
51
|
+
"sass": "1.80.7",
|
|
52
|
+
"sass-loader": "16.0.3",
|
|
53
53
|
"semver": "7.6.3",
|
|
54
54
|
"source-map-loader": "5.0.0",
|
|
55
55
|
"source-map-support": "0.5.21",
|
|
56
56
|
"terser": "5.36.0",
|
|
57
57
|
"tree-kill": "1.2.2",
|
|
58
|
-
"tslib": "2.8.
|
|
59
|
-
"webpack": "5.
|
|
58
|
+
"tslib": "2.8.1",
|
|
59
|
+
"webpack": "5.96.1",
|
|
60
60
|
"webpack-dev-middleware": "7.4.2",
|
|
61
61
|
"webpack-dev-server": "5.1.0",
|
|
62
62
|
"webpack-merge": "6.0.1",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@angular/localize": "^19.0.0-next.0",
|
|
71
71
|
"@angular/platform-server": "^19.0.0-next.0",
|
|
72
72
|
"@angular/service-worker": "^19.0.0-next.0",
|
|
73
|
-
"@angular/ssr": "^19.0.0-rc.
|
|
73
|
+
"@angular/ssr": "^19.0.0-rc.2",
|
|
74
74
|
"@web/test-runner": "^0.19.0",
|
|
75
75
|
"browser-sync": "^3.0.2",
|
|
76
76
|
"jest": "^29.5.0",
|
|
@@ -72,6 +72,8 @@ function execute(options, context, transforms = {}, extensions) {
|
|
|
72
72
|
if (options.disableHostCheck) {
|
|
73
73
|
context.logger.warn(`The "disableHostCheck" option will not be used because it is not supported by the "${builderName}" builder.`);
|
|
74
74
|
}
|
|
75
|
+
// New build system defaults hmr option to the value of liveReload
|
|
76
|
+
normalizedOptions.hmr ??= normalizedOptions.liveReload;
|
|
75
77
|
return (0, rxjs_1.defer)(() => Promise.all([Promise.resolve().then(() => __importStar(require('@angular/build/private'))), Promise.resolve().then(() => __importStar(require('../browser-esbuild')))])).pipe((0, rxjs_1.switchMap)(([{ serveWithVite, buildApplicationInternal }, { convertBrowserOptions }]) => serveWithVite(normalizedOptions, builderName, (options, context, codePlugins) => {
|
|
76
78
|
return builderName === '@angular-devkit/build-angular:browser-esbuild'
|
|
77
79
|
? // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -91,6 +93,8 @@ function execute(options, context, transforms = {}, extensions) {
|
|
|
91
93
|
if (extensions?.middleware?.length) {
|
|
92
94
|
throw new Error('Only the "application" and "browser-esbuild" builders support middleware.');
|
|
93
95
|
}
|
|
96
|
+
// Webpack based build systems default to false for hmr option
|
|
97
|
+
normalizedOptions.hmr ??= false;
|
|
94
98
|
// Use Webpack for all other browser targets
|
|
95
99
|
return (0, rxjs_1.defer)(() => Promise.resolve().then(() => __importStar(require('./webpack-server')))).pipe((0, rxjs_1.switchMap)(({ serveWebpackBrowser }) => serveWebpackBrowser(normalizedOptions, builderName, context, transforms)));
|
|
96
100
|
}));
|
|
@@ -26,7 +26,7 @@ export declare function normalizeOptions(context: BuilderContext, projectName: s
|
|
|
26
26
|
open: boolean | undefined;
|
|
27
27
|
verbose: boolean | undefined;
|
|
28
28
|
watch: boolean | undefined;
|
|
29
|
-
liveReload: boolean
|
|
29
|
+
liveReload: boolean;
|
|
30
30
|
hmr: boolean | undefined;
|
|
31
31
|
headers: {
|
|
32
32
|
[key: string]: string;
|
|
@@ -50,26 +50,84 @@ class ApplicationBuildError extends Error {
|
|
|
50
50
|
this.name = 'ApplicationBuildError';
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
const LATEST_BUILD_FILES_TOKEN = 'angularLatestBuildFiles';
|
|
54
|
+
class AngularAssetsMiddleware {
|
|
55
|
+
serveFile;
|
|
56
|
+
latestBuildFiles;
|
|
57
|
+
static $inject = ['serveFile', LATEST_BUILD_FILES_TOKEN];
|
|
58
|
+
static NAME = 'angular-test-assets';
|
|
59
|
+
constructor(serveFile, latestBuildFiles) {
|
|
60
|
+
this.serveFile = serveFile;
|
|
61
|
+
this.latestBuildFiles = latestBuildFiles;
|
|
62
|
+
}
|
|
63
|
+
handle(req, res, next) {
|
|
64
|
+
let err = null;
|
|
65
|
+
try {
|
|
66
|
+
const url = new URL(`http://${req.headers['host']}${req.url}`);
|
|
67
|
+
const file = this.latestBuildFiles.files[url.pathname.slice(1)];
|
|
68
|
+
if (file?.origin === 'disk') {
|
|
69
|
+
this.serveFile(file.inputPath, undefined, res);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
else if (file?.origin === 'memory') {
|
|
73
|
+
// Include pathname to help with Content-Type headers.
|
|
74
|
+
this.serveFile(`/unused/${url.pathname}`, undefined, res, undefined, file.contents, true);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
err = e;
|
|
80
|
+
}
|
|
81
|
+
next(err);
|
|
82
|
+
}
|
|
83
|
+
static createPlugin(initialFiles) {
|
|
84
|
+
return {
|
|
85
|
+
[LATEST_BUILD_FILES_TOKEN]: ['value', { files: { ...initialFiles.files } }],
|
|
86
|
+
[`middleware:${AngularAssetsMiddleware.NAME}`]: [
|
|
87
|
+
'factory',
|
|
88
|
+
Object.assign((...args) => {
|
|
89
|
+
const inst = new AngularAssetsMiddleware(...args);
|
|
90
|
+
return inst.handle.bind(inst);
|
|
91
|
+
}, AngularAssetsMiddleware),
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function injectKarmaReporter(context, buildOptions, buildIterator, karmaConfig, subscriber) {
|
|
54
97
|
const reporterName = 'angular-progress-notifier';
|
|
55
98
|
class ProgressNotifierReporter {
|
|
56
99
|
emitter;
|
|
57
|
-
|
|
58
|
-
|
|
100
|
+
latestBuildFiles;
|
|
101
|
+
static $inject = ['emitter', LATEST_BUILD_FILES_TOKEN];
|
|
102
|
+
constructor(emitter, latestBuildFiles) {
|
|
59
103
|
this.emitter = emitter;
|
|
104
|
+
this.latestBuildFiles = latestBuildFiles;
|
|
60
105
|
this.startWatchingBuild();
|
|
61
106
|
}
|
|
62
107
|
startWatchingBuild() {
|
|
63
108
|
void (async () => {
|
|
64
|
-
for await
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
109
|
+
// This is effectively "for await of but skip what's already consumed".
|
|
110
|
+
let isDone = false; // to mark the loop condition as "not constant".
|
|
111
|
+
while (!isDone) {
|
|
112
|
+
const { done, value: buildOutput } = await buildIterator.next();
|
|
113
|
+
if (done) {
|
|
114
|
+
isDone = true;
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
68
117
|
if (buildOutput.kind === private_1.ResultKind.Failure) {
|
|
69
118
|
subscriber.next({ success: false, message: 'Build failed' });
|
|
70
119
|
}
|
|
71
120
|
else if (buildOutput.kind === private_1.ResultKind.Incremental ||
|
|
72
121
|
buildOutput.kind === private_1.ResultKind.Full) {
|
|
122
|
+
if (buildOutput.kind === private_1.ResultKind.Full) {
|
|
123
|
+
this.latestBuildFiles.files = buildOutput.files;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.latestBuildFiles.files = {
|
|
127
|
+
...this.latestBuildFiles.files,
|
|
128
|
+
...buildOutput.files,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
73
131
|
await writeTestFiles(buildOutput.files, buildOptions.outputPath);
|
|
74
132
|
this.emitter.refreshFiles();
|
|
75
133
|
}
|
|
@@ -96,11 +154,11 @@ function injectKarmaReporter(context, buildOptions, karmaConfig, subscriber) {
|
|
|
96
154
|
});
|
|
97
155
|
}
|
|
98
156
|
function execute(options, context, karmaOptions, transforms = {}) {
|
|
99
|
-
return (0, rxjs_1.from)(initializeApplication(options, context, karmaOptions, transforms)).pipe((0, rxjs_1.switchMap)(([karma, karmaConfig, buildOptions]) => new rxjs_1.Observable((subscriber) => {
|
|
157
|
+
return (0, rxjs_1.from)(initializeApplication(options, context, karmaOptions, transforms)).pipe((0, rxjs_1.switchMap)(([karma, karmaConfig, buildOptions, buildIterator]) => new rxjs_1.Observable((subscriber) => {
|
|
100
158
|
// If `--watch` is explicitly enabled or if we are keeping the Karma
|
|
101
159
|
// process running, we should hook Karma into the build.
|
|
102
|
-
if (
|
|
103
|
-
injectKarmaReporter(context, buildOptions, karmaConfig, subscriber);
|
|
160
|
+
if (buildIterator) {
|
|
161
|
+
injectKarmaReporter(context, buildOptions, buildIterator, karmaConfig, subscriber);
|
|
104
162
|
}
|
|
105
163
|
// Complete the observable once the Karma server returns.
|
|
106
164
|
const karmaServer = new karma.Server(karmaConfig, (exitCode) => {
|
|
@@ -138,7 +196,21 @@ function normalizePolyfills(polyfills) {
|
|
|
138
196
|
async function collectEntrypoints(options, context, projectSourceRoot) {
|
|
139
197
|
// Glob for files to test.
|
|
140
198
|
const testFiles = await (0, find_tests_1.findTests)(options.include ?? [], options.exclude ?? [], context.workspaceRoot, projectSourceRoot);
|
|
141
|
-
|
|
199
|
+
const seen = new Set();
|
|
200
|
+
return new Map(Array.from(testFiles, (testFile) => {
|
|
201
|
+
const relativePath = path
|
|
202
|
+
.relative(testFile.startsWith(projectSourceRoot) ? projectSourceRoot : context.workspaceRoot, testFile)
|
|
203
|
+
.replace(/^[./]+/, '_')
|
|
204
|
+
.replace(/\//g, '-');
|
|
205
|
+
let uniqueName = `spec-${path.basename(relativePath, path.extname(relativePath))}`;
|
|
206
|
+
let suffix = 2;
|
|
207
|
+
while (seen.has(uniqueName)) {
|
|
208
|
+
uniqueName = `${relativePath}-${suffix}`;
|
|
209
|
+
++suffix;
|
|
210
|
+
}
|
|
211
|
+
seen.add(uniqueName);
|
|
212
|
+
return [uniqueName, testFile];
|
|
213
|
+
}));
|
|
142
214
|
}
|
|
143
215
|
async function initializeApplication(options, context, karmaOptions, transforms = {}) {
|
|
144
216
|
if (transforms.webpackConfiguration) {
|
|
@@ -151,18 +223,18 @@ async function initializeApplication(options, context, karmaOptions, transforms
|
|
|
151
223
|
collectEntrypoints(options, context, projectSourceRoot),
|
|
152
224
|
fs.rm(outputPath, { recursive: true, force: true }),
|
|
153
225
|
]);
|
|
154
|
-
|
|
226
|
+
const mainName = 'test_main';
|
|
155
227
|
if (options.main) {
|
|
156
|
-
entryPoints.
|
|
157
|
-
mainName = path.basename(options.main, path.extname(options.main));
|
|
228
|
+
entryPoints.set(mainName, options.main);
|
|
158
229
|
}
|
|
159
230
|
else {
|
|
160
|
-
entryPoints.
|
|
231
|
+
entryPoints.set(mainName, '@angular-devkit/build-angular/src/builders/karma/init_test_bed.js');
|
|
161
232
|
}
|
|
162
233
|
const instrumentForCoverage = options.codeCoverage
|
|
163
234
|
? createInstrumentationFilter(projectSourceRoot, getInstrumentationExcludedPaths(context.workspaceRoot, options.codeCoverageExclude ?? []))
|
|
164
235
|
: undefined;
|
|
165
236
|
const buildOptions = {
|
|
237
|
+
assets: options.assets,
|
|
166
238
|
entryPoints,
|
|
167
239
|
tsConfig: options.tsConfig,
|
|
168
240
|
outputPath,
|
|
@@ -179,9 +251,10 @@ async function initializeApplication(options, context, karmaOptions, transforms
|
|
|
179
251
|
styles: options.styles,
|
|
180
252
|
polyfills: normalizePolyfills(options.polyfills),
|
|
181
253
|
webWorkerTsConfig: options.webWorkerTsConfig,
|
|
254
|
+
watch: options.watch ?? !karmaOptions.singleRun,
|
|
182
255
|
};
|
|
183
256
|
// Build tests with `application` builder, using test files as entry points.
|
|
184
|
-
const buildOutput = await first((0, private_1.buildApplicationInternal)(buildOptions, context));
|
|
257
|
+
const [buildOutput, buildIterator] = await first((0, private_1.buildApplicationInternal)(buildOptions, context), { cancel: !buildOptions.watch });
|
|
185
258
|
if (buildOutput.kind === private_1.ResultKind.Failure) {
|
|
186
259
|
throw new ApplicationBuildError('Build failed');
|
|
187
260
|
}
|
|
@@ -193,46 +266,55 @@ async function initializeApplication(options, context, karmaOptions, transforms
|
|
|
193
266
|
karmaOptions.files ??= [];
|
|
194
267
|
karmaOptions.files.push(
|
|
195
268
|
// Serve polyfills first.
|
|
196
|
-
{ pattern: `${outputPath}/polyfills.js`, type: 'module' },
|
|
269
|
+
{ pattern: `${outputPath}/polyfills.js`, type: 'module', watched: false },
|
|
197
270
|
// Serve global setup script.
|
|
198
|
-
{ pattern: `${outputPath}/${mainName}.js`, type: 'module' },
|
|
271
|
+
{ pattern: `${outputPath}/${mainName}.js`, type: 'module', watched: false },
|
|
199
272
|
// Serve all source maps.
|
|
200
|
-
{ pattern: `${outputPath}/*.map`, included: false }
|
|
273
|
+
{ pattern: `${outputPath}/*.map`, included: false, watched: false },
|
|
274
|
+
// These are the test entrypoints.
|
|
275
|
+
{ pattern: `${outputPath}/spec-*.js`, type: 'module', watched: false });
|
|
201
276
|
if (hasChunkOrWorkerFiles(buildOutput.files)) {
|
|
202
277
|
karmaOptions.files.push(
|
|
203
278
|
// Allow loading of chunk-* files but don't include them all on load.
|
|
204
|
-
{
|
|
279
|
+
{
|
|
280
|
+
pattern: `${outputPath}/{chunk,worker}-*.js`,
|
|
281
|
+
type: 'module',
|
|
282
|
+
included: false,
|
|
283
|
+
watched: false,
|
|
284
|
+
});
|
|
205
285
|
}
|
|
206
|
-
karmaOptions.files.push(
|
|
207
|
-
// Serve remaining JS on page load, these are the test entrypoints.
|
|
208
|
-
{ pattern: `${outputPath}/*.js`, type: 'module' });
|
|
209
286
|
if (options.styles?.length) {
|
|
210
287
|
// Serve CSS outputs on page load, these are the global styles.
|
|
211
|
-
karmaOptions.files.push({ pattern: `${outputPath}/*.css`, type: 'css' });
|
|
288
|
+
karmaOptions.files.push({ pattern: `${outputPath}/*.css`, type: 'css', watched: false });
|
|
212
289
|
}
|
|
213
290
|
const parsedKarmaConfig = await karma.config.parseConfig(options.karmaConfig && path.resolve(context.workspaceRoot, options.karmaConfig), transforms.karmaOptions ? transforms.karmaOptions(karmaOptions) : karmaOptions, { promiseConfig: true, throwErrors: true });
|
|
214
291
|
// Remove the webpack plugin/framework:
|
|
215
292
|
// Alternative would be to make the Karma plugin "smart" but that's a tall order
|
|
216
293
|
// with managing unneeded imports etc..
|
|
217
|
-
|
|
218
|
-
|
|
294
|
+
parsedKarmaConfig.plugins ??= [];
|
|
295
|
+
const pluginLengthBefore = parsedKarmaConfig.plugins.length;
|
|
296
|
+
parsedKarmaConfig.plugins = parsedKarmaConfig.plugins.filter((plugin) => {
|
|
219
297
|
if (typeof plugin === 'string') {
|
|
220
298
|
return plugin !== 'framework:@angular-devkit/build-angular';
|
|
221
299
|
}
|
|
222
300
|
return !plugin['framework:@angular-devkit/build-angular'];
|
|
223
301
|
});
|
|
224
|
-
parsedKarmaConfig.frameworks
|
|
225
|
-
|
|
302
|
+
parsedKarmaConfig.frameworks ??= [];
|
|
303
|
+
parsedKarmaConfig.frameworks = parsedKarmaConfig.frameworks.filter((framework) => framework !== '@angular-devkit/build-angular');
|
|
304
|
+
const pluginLengthAfter = parsedKarmaConfig.plugins.length;
|
|
226
305
|
if (pluginLengthBefore !== pluginLengthAfter) {
|
|
227
306
|
context.logger.warn(`Ignoring framework "@angular-devkit/build-angular" from karma config file because it's not compatible with the application builder.`);
|
|
228
307
|
}
|
|
308
|
+
parsedKarmaConfig.plugins.push(AngularAssetsMiddleware.createPlugin(buildOutput));
|
|
309
|
+
parsedKarmaConfig.middleware ??= [];
|
|
310
|
+
parsedKarmaConfig.middleware.push(AngularAssetsMiddleware.NAME);
|
|
229
311
|
// When using code-coverage, auto-add karma-coverage.
|
|
230
312
|
// This was done as part of the karma plugin for webpack.
|
|
231
313
|
if (options.codeCoverage &&
|
|
232
314
|
!parsedKarmaConfig.reporters?.some((r) => r === 'coverage' || r === 'coverage-istanbul')) {
|
|
233
315
|
parsedKarmaConfig.reporters = (parsedKarmaConfig.reporters ?? []).concat(['coverage']);
|
|
234
316
|
}
|
|
235
|
-
return [karma, parsedKarmaConfig, buildOptions];
|
|
317
|
+
return [karma, parsedKarmaConfig, buildOptions, buildIterator];
|
|
236
318
|
}
|
|
237
319
|
function hasChunkOrWorkerFiles(files) {
|
|
238
320
|
return Object.keys(files).some((filename) => {
|
|
@@ -264,9 +346,17 @@ async function writeTestFiles(files, testDir) {
|
|
|
264
346
|
});
|
|
265
347
|
}
|
|
266
348
|
/** Returns the first item yielded by the given generator and cancels the execution. */
|
|
267
|
-
async function first(generator) {
|
|
349
|
+
async function first(generator, { cancel }) {
|
|
350
|
+
if (!cancel) {
|
|
351
|
+
const iterator = generator[Symbol.asyncIterator]();
|
|
352
|
+
const firstValue = await iterator.next();
|
|
353
|
+
if (firstValue.done) {
|
|
354
|
+
throw new Error('Expected generator to emit at least once.');
|
|
355
|
+
}
|
|
356
|
+
return [firstValue.value, iterator];
|
|
357
|
+
}
|
|
268
358
|
for await (const value of generator) {
|
|
269
|
-
return value;
|
|
359
|
+
return [value, null];
|
|
270
360
|
}
|
|
271
361
|
throw new Error('Expected generator to emit at least once.');
|
|
272
362
|
}
|
|
@@ -10,7 +10,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.normalizeCacheOptions = normalizeCacheOptions;
|
|
11
11
|
const node_path_1 = require("node:path");
|
|
12
12
|
/** Version placeholder is replaced during the build process with actual package version */
|
|
13
|
-
const VERSION = '19.0.0-rc.
|
|
13
|
+
const VERSION = '19.0.0-rc.2';
|
|
14
14
|
function hasCacheMetadata(value) {
|
|
15
15
|
return (!!value &&
|
|
16
16
|
typeof value === 'object' &&
|