mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-20 21:42:38 +08:00
feat(@schematics/angular): add support to add service worker to standalone application
This commit adds support to generate a service worker in a standalone application.
This commit is contained in:
parent
584b51907c
commit
c2d2da41b1
@ -163,6 +163,7 @@ export function addModuleImportToStandaloneBootstrap(
|
||||
* @param functionName Name of the function that should be called.
|
||||
* @param importPath Path from which to import the function.
|
||||
* @param args Arguments to use when calling the function.
|
||||
* @returns The file path that the provider was added to.
|
||||
*/
|
||||
export function addFunctionalProvidersToStandaloneBootstrap(
|
||||
tree: Tree,
|
||||
@ -170,7 +171,7 @@ export function addFunctionalProvidersToStandaloneBootstrap(
|
||||
functionName: string,
|
||||
importPath: string,
|
||||
args: ts.Expression[] = [],
|
||||
) {
|
||||
): string {
|
||||
const sourceFile = createSourceFile(tree, filePath);
|
||||
const bootstrapCall = findBootstrapApplicationCall(sourceFile);
|
||||
const addImports = (file: ts.SourceFile, recorder: UpdateRecorder) => {
|
||||
@ -198,7 +199,7 @@ export function addFunctionalProvidersToStandaloneBootstrap(
|
||||
addImports(sourceFile, recorder);
|
||||
tree.commitUpdate(recorder);
|
||||
|
||||
return;
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// If the config is a `mergeApplicationProviders` call, add another config to it.
|
||||
@ -208,7 +209,7 @@ export function addFunctionalProvidersToStandaloneBootstrap(
|
||||
addImports(sourceFile, recorder);
|
||||
tree.commitUpdate(recorder);
|
||||
|
||||
return;
|
||||
return filePath;
|
||||
}
|
||||
|
||||
// Otherwise attempt to merge into the current config.
|
||||
@ -235,6 +236,8 @@ export function addFunctionalProvidersToStandaloneBootstrap(
|
||||
}
|
||||
|
||||
tree.commitUpdate(recorder);
|
||||
|
||||
return configFilePath;
|
||||
}
|
||||
|
||||
/** Finds the call to `bootstrapApplication` within a file. */
|
||||
|
@ -20,12 +20,13 @@ import {
|
||||
url,
|
||||
} from '@angular-devkit/schematics';
|
||||
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
|
||||
import { addFunctionalProvidersToStandaloneBootstrap } from '../private/standalone';
|
||||
import * as ts from '../third_party/github.com/Microsoft/TypeScript/lib/typescript';
|
||||
import { readWorkspace, writeWorkspace } from '../utility';
|
||||
import { addSymbolToNgModuleMetadata, insertImport } from '../utility/ast-utils';
|
||||
import { applyToUpdateRecorder } from '../utility/change';
|
||||
import { addPackageJsonDependency, getPackageJsonDependency } from '../utility/dependencies';
|
||||
import { getAppModulePath } from '../utility/ng-ast-utils';
|
||||
import { getAppModulePath, isStandaloneApp } from '../utility/ng-ast-utils';
|
||||
import { relativePathToWorkspaceRoot } from '../utility/paths';
|
||||
import { targetBuildNotFoundError } from '../utility/project-targets';
|
||||
import { BrowserBuilderOptions } from '../utility/workspace-models';
|
||||
@ -85,6 +86,44 @@ function updateAppModule(mainPath: string): Rule {
|
||||
};
|
||||
}
|
||||
|
||||
function addProvideServiceWorker(mainPath: string): Rule {
|
||||
return (host: Tree) => {
|
||||
const updatedFilePath = addFunctionalProvidersToStandaloneBootstrap(
|
||||
host,
|
||||
mainPath,
|
||||
'provideServiceWorker',
|
||||
'@angular/service-worker',
|
||||
[
|
||||
ts.factory.createStringLiteral('ngsw-worker.js', true),
|
||||
ts.factory.createObjectLiteralExpression(
|
||||
[
|
||||
ts.factory.createPropertyAssignment(
|
||||
ts.factory.createIdentifier('enabled'),
|
||||
ts.factory.createPrefixUnaryExpression(
|
||||
ts.SyntaxKind.ExclamationToken,
|
||||
ts.factory.createCallExpression(
|
||||
ts.factory.createIdentifier('isDevMode'),
|
||||
undefined,
|
||||
[],
|
||||
),
|
||||
),
|
||||
),
|
||||
ts.factory.createPropertyAssignment(
|
||||
ts.factory.createIdentifier('registrationStrategy'),
|
||||
ts.factory.createStringLiteral('registerWhenStable:30000', true),
|
||||
),
|
||||
],
|
||||
true,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
addImport(host, updatedFilePath, 'isDevMode', '@angular/core');
|
||||
|
||||
return host;
|
||||
};
|
||||
}
|
||||
|
||||
function getTsSourceFile(host: Tree, path: string): ts.SourceFile {
|
||||
const content = host.readText(path);
|
||||
const source = ts.createSourceFile(path, content, ts.ScriptTarget.Latest, true);
|
||||
@ -116,23 +155,25 @@ export default function (options: ServiceWorkerOptions): Rule {
|
||||
resourcesOutputPath = normalize(`/${resourcesOutputPath}`);
|
||||
}
|
||||
|
||||
const templateSource = apply(url('./files'), [
|
||||
context.addTask(new NodePackageInstallTask());
|
||||
|
||||
await writeWorkspace(host, workspace);
|
||||
|
||||
const { main } = buildOptions;
|
||||
|
||||
return chain([
|
||||
mergeWith(
|
||||
apply(url('./files'), [
|
||||
applyTemplates({
|
||||
...options,
|
||||
resourcesOutputPath,
|
||||
relativePathToWorkspaceRoot: relativePathToWorkspaceRoot(project.root),
|
||||
}),
|
||||
move(project.root),
|
||||
]);
|
||||
|
||||
context.addTask(new NodePackageInstallTask());
|
||||
|
||||
await writeWorkspace(host, workspace);
|
||||
|
||||
return chain([
|
||||
mergeWith(templateSource),
|
||||
]),
|
||||
),
|
||||
addDependencies(),
|
||||
updateAppModule(buildOptions.main),
|
||||
isStandaloneApp(host, main) ? addProvideServiceWorker(main) : updateAppModule(main),
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import { tags } from '@angular-devkit/core';
|
||||
import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
|
||||
import { Schema as ApplicationOptions } from '../application/schema';
|
||||
import { Schema as WorkspaceOptions } from '../workspace/schema';
|
||||
@ -164,4 +165,56 @@ describe('Service Worker Schematic', () => {
|
||||
const { projects } = JSON.parse(tree.readContent('/angular.json'));
|
||||
expect(projects.foo.architect.build.options.ngswConfigPath).toBe('ngsw-config.json');
|
||||
});
|
||||
|
||||
describe('standalone', () => {
|
||||
const name = 'buz';
|
||||
const standaloneAppOptions: ApplicationOptions = {
|
||||
...appOptions,
|
||||
name,
|
||||
standalone: true,
|
||||
};
|
||||
const standaloneSWOptions: ServiceWorkerOptions = {
|
||||
...defaultOptions,
|
||||
project: name,
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
appTree = await schematicRunner.runSchematic('application', standaloneAppOptions, appTree);
|
||||
});
|
||||
|
||||
it(`should add the 'provideServiceWorker' to providers`, async () => {
|
||||
const tree = await schematicRunner.runSchematic(
|
||||
'service-worker',
|
||||
standaloneSWOptions,
|
||||
appTree,
|
||||
);
|
||||
const content = tree.readContent('/projects/buz/src/app/app.config.ts');
|
||||
expect(tags.oneLine`${content}`).toContain(tags.oneLine`
|
||||
providers: [provideServiceWorker('ngsw-worker.js', {
|
||||
enabled: !isDevMode(),
|
||||
registrationStrategy: 'registerWhenStable:30000'
|
||||
})]
|
||||
`);
|
||||
});
|
||||
|
||||
it(`should import 'isDevMode' from '@angular/core'`, async () => {
|
||||
const tree = await schematicRunner.runSchematic(
|
||||
'service-worker',
|
||||
standaloneSWOptions,
|
||||
appTree,
|
||||
);
|
||||
const content = tree.readContent('/projects/buz/src/app/app.config.ts');
|
||||
expect(content).toContain(`import { ApplicationConfig, isDevMode } from '@angular/core';`);
|
||||
});
|
||||
|
||||
it(`should import 'provideServiceWorker' from '@angular/service-worker'`, async () => {
|
||||
const tree = await schematicRunner.runSchematic(
|
||||
'service-worker',
|
||||
standaloneSWOptions,
|
||||
appTree,
|
||||
);
|
||||
const content = tree.readContent('/projects/buz/src/app/app.config.ts');
|
||||
expect(content).toContain(`import { provideServiceWorker } from '@angular/service-worker';`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user