angular-cli/packages/@angular/cli/plugins/glob-copy-webpack-plugin.ts
Alex Rickabaugh cb2e418d58
feat: add support for @angular/service-worker and manifest generation
Adds the flag 'serviceWorker' to angular-cli.json that enables support for @angular/service-worker.

When this flag is true, production builds will be set up with a service worker. A ngsw-manifest.json file
will be generated (or augmented) in the dist/ root, and the service worker script will be copied there.
A short script will be added to index.html to register the service worker.

@angular/service-worker is a dependency of @angular/cli, but not of generated projects. It is desirable
for users to be able to update the version of @angular/service-worker used in their apps independently
of the CLI version. Thus, the CLI will error if serviceWorker=true but @angular/service-worker is not
installed in the application's node_modules, as it pulls all the service worker scripts from there.

If the flag is false the effect on the CLI is minimal - the webpack plugins associated with the SW are
not even require()'d.

Closes #4544
2017-02-09 15:16:48 -08:00

63 lines
1.9 KiB
TypeScript

import * as fs from 'fs';
import * as path from 'path';
import * as glob from 'glob';
import * as denodeify from 'denodeify';
const globPromise = <any>denodeify(glob);
const statPromise = <any>denodeify(fs.stat);
function isDirectory(path: string) {
try {
return fs.statSync(path).isDirectory();
} catch (_) {
return false;
}
}
export interface GlobCopyWebpackPluginOptions {
patterns: string[];
globOptions: any;
}
export class GlobCopyWebpackPlugin {
constructor(private options: GlobCopyWebpackPluginOptions) { }
apply(compiler: any): void {
let { patterns, globOptions } = this.options;
let context = globOptions.cwd || compiler.options.context;
let optional = !!globOptions.optional;
// convert dir patterns to globs
patterns = patterns.map(pattern => isDirectory(path.resolve(context, pattern))
? pattern += '/**/*'
: pattern
);
// force nodir option, since we can't add dirs to assets
globOptions.nodir = true;
compiler.plugin('emit', (compilation: any, cb: any) => {
let globs = patterns.map(pattern => globPromise(pattern, globOptions));
let addAsset = (relPath: string) => compilation.assets[relPath]
// don't re-add to assets
? Promise.resolve()
: statPromise(path.resolve(context, relPath))
.then((stat: any) => compilation.assets[relPath] = {
size: () => stat.size,
source: () => fs.readFileSync(path.resolve(context, relPath))
})
.catch((err: any) => optional ? Promise.resolve() : Promise.reject(err));
Promise.all(globs)
// flatten results
.then(globResults => [].concat.apply([], globResults))
// add each file to compilation assets
.then((relPaths: string[]) =>
Promise.all(relPaths.map((relPath: string) => addAsset(relPath))))
.catch((err) => compilation.errors.push(err))
.then(() => cb());
});
}
}