diff --git a/docs/documentation/build.md b/docs/documentation/build.md index f21cf381d4f6..0c1cdeef7d7a 100644 --- a/docs/documentation/build.md +++ b/docs/documentation/build.md @@ -35,3 +35,5 @@ ng build `--base-href` (`-bh`) base url for the application being built `--aot` flag whether to build using Ahead of Time compilation + +`--extract-css` extract css from global styles onto css files instead of js ones diff --git a/docs/documentation/serve.md b/docs/documentation/serve.md index 5dd8f5582feb..b6d627c78023 100644 --- a/docs/documentation/serve.md +++ b/docs/documentation/serve.md @@ -34,4 +34,6 @@ `--aot` flag to turn on Ahead of Time compilation -`--open` (`-o`) opens the app in the default browser \ No newline at end of file +`--open` (`-o`) opens the app in the default browser + +`--extract-css` extract css from global styles onto css files instead of js ones diff --git a/packages/angular-cli/commands/build.ts b/packages/angular-cli/commands/build.ts index 245ac7d849dc..b9ed1f6c35f6 100644 --- a/packages/angular-cli/commands/build.ts +++ b/packages/angular-cli/commands/build.ts @@ -18,6 +18,7 @@ export interface BuildOptions { locale?: string; deployUrl?: string; outputHashing?: string; + extractCss?: boolean | null; } const BuildCommand = Command.extend({ @@ -52,7 +53,8 @@ const BuildCommand = Command.extend({ type: String, values: ['none', 'all', 'media', 'bundles'], description: 'define the output filename cache-busting hashing mode' - } + }, + { name: 'extract-css', type: Boolean, default: true } ], run: function (commandOptions: BuildOptions) { diff --git a/packages/angular-cli/commands/serve.run.ts b/packages/angular-cli/commands/serve.run.ts index 037d4062df15..4f32703e15f5 100644 --- a/packages/angular-cli/commands/serve.run.ts +++ b/packages/angular-cli/commands/serve.run.ts @@ -20,6 +20,11 @@ export default function serveRun(commandOptions: ServeTaskOptions) { } } + // default to extractCss to true on prod target + if (typeof commandOptions.extractCss === 'undefined') { + commandOptions.extractCss = commandOptions.target === 'production'; + } + // Check angular version. Version.assertAngularVersionIs2_3_1OrHigher(this.project.root); commandOptions.liveReloadHost = commandOptions.liveReloadHost || commandOptions.host; diff --git a/packages/angular-cli/commands/serve.ts b/packages/angular-cli/commands/serve.ts index a9ce848d13ae..a1af11e528e6 100644 --- a/packages/angular-cli/commands/serve.ts +++ b/packages/angular-cli/commands/serve.ts @@ -30,6 +30,7 @@ export interface ServeTaskOptions { i18nFile?: string; i18nFormat?: string; locale?: string; + extractCss?: boolean | null; } const ServeCommand = Command.extend({ @@ -103,7 +104,8 @@ const ServeCommand = Command.extend({ }, { name: 'i18n-file', type: String, default: null }, { name: 'i18n-format', type: String, default: null }, - { name: 'locale', type: String, default: null } + { name: 'locale', type: String, default: null }, + { name: 'extract-css', type: Boolean, default: null } ], run: function(commandOptions: ServeTaskOptions) { diff --git a/packages/angular-cli/models/webpack-build-common.ts b/packages/angular-cli/models/webpack-build-common.ts index b7493d287c89..6325ddd84ad4 100644 --- a/packages/angular-cli/models/webpack-build-common.ts +++ b/packages/angular-cli/models/webpack-build-common.ts @@ -34,6 +34,7 @@ export function getWebpackCommonConfig( verbose: boolean, progress: boolean, outputHashing: string, + extractCss: boolean, ) { const appRoot = path.resolve(projectRoot, appConfig.root); @@ -91,7 +92,7 @@ export function getWebpackCommonConfig( // create css loaders for component css and for global css extraRules.push(...makeCssLoaders(globalStyles.map((style) => style.path))); - if (extractedCssEntryPoints.length > 0) { + if (extractCss && extractedCssEntryPoints.length > 0) { // don't emit the .js entry point for extracted styles extraPlugins.push(new SuppressEntryChunksWebpackPlugin({ chunks: extractedCssEntryPoints })); } @@ -172,7 +173,10 @@ export function getWebpackCommonConfig( ].concat(extraRules) }, plugins: [ - new ExtractTextPlugin(`[name]${hashFormat.extract}.bundle.css`), + new ExtractTextPlugin({ + filename: `[name]${hashFormat.extract}.bundle.css`, + disable: !extractCss + }), new HtmlWebpackPlugin({ template: path.resolve(appRoot, appConfig.index), filename: path.resolve(appConfig.outDir, appConfig.index), diff --git a/packages/angular-cli/models/webpack-config.ts b/packages/angular-cli/models/webpack-config.ts index cc9e942b212a..84316db0ff90 100644 --- a/packages/angular-cli/models/webpack-config.ts +++ b/packages/angular-cli/models/webpack-config.ts @@ -33,7 +33,8 @@ export class NgCliWebpackConfig { verbose = false, progress = true, deployUrl?: string, - outputHashing?: string + outputHashing?: string, + extractCss = true, ) { const config: CliConfig = CliConfig.fromProject(); const appConfig = config.config.apps[0]; @@ -50,7 +51,8 @@ export class NgCliWebpackConfig { vendorChunk, verbose, progress, - outputHashing + outputHashing, + extractCss, ); let targetConfigPartial = this.getTargetConfig( this.ngCliProject.root, appConfig, sourcemap, verbose diff --git a/packages/angular-cli/tasks/build-webpack-watch.ts b/packages/angular-cli/tasks/build-webpack-watch.ts index 4e07802bce61..5ef0d9283c2f 100644 --- a/packages/angular-cli/tasks/build-webpack-watch.ts +++ b/packages/angular-cli/tasks/build-webpack-watch.ts @@ -34,7 +34,8 @@ export default Task.extend({ runTaskOptions.verbose, runTaskOptions.progress, deployUrl, - runTaskOptions.outputHashing + runTaskOptions.outputHashing, + runTaskOptions.extractCss, ).config; const webpackCompiler: any = webpack(config); diff --git a/packages/angular-cli/tasks/build-webpack.ts b/packages/angular-cli/tasks/build-webpack.ts index 78b770099c6b..c1b68b7189d9 100644 --- a/packages/angular-cli/tasks/build-webpack.ts +++ b/packages/angular-cli/tasks/build-webpack.ts @@ -35,7 +35,8 @@ export default Task.extend({ runTaskOptions.verbose, runTaskOptions.progress, deployUrl, - runTaskOptions.outputHashing + runTaskOptions.outputHashing, + runTaskOptions.extractCss, ).config; const webpackCompiler: any = webpack(config); diff --git a/packages/angular-cli/tasks/serve-webpack.ts b/packages/angular-cli/tasks/serve-webpack.ts index 43f13b233f13..844899b59f3c 100644 --- a/packages/angular-cli/tasks/serve-webpack.ts +++ b/packages/angular-cli/tasks/serve-webpack.ts @@ -35,7 +35,10 @@ export default Task.extend({ serveTaskOptions.sourcemap, serveTaskOptions.vendorChunk, serveTaskOptions.verbose, - serveTaskOptions.progress + serveTaskOptions.progress, + undefined, + undefined, + serveTaskOptions.extractCss ).config; // This allows for live reload of page when changes are made to repo. @@ -55,6 +58,12 @@ export default Task.extend({ ui.writeLine(' for information on working with HMR for Webpack.'); entryPoints.push('webpack/hot/dev-server'); config.plugins.push(new webpack.HotModuleReplacementPlugin()); + if (serveTaskOptions.extractCss) { + ui.writeLine(oneLine` + ${chalk.yellow('NOTICE')} (HMR) does not allow for CSS hot reload when used + together with '--extract-css'. + `); + } } config.entry.main.unshift(...entryPoints); webpackCompiler = webpack(config); diff --git a/tests/e2e/tests/build/styles/styles-array.ts b/tests/e2e/tests/build/styles/styles-array.ts index f85b4d387cbd..e43c03160914 100644 --- a/tests/e2e/tests/build/styles/styles-array.ts +++ b/tests/e2e/tests/build/styles/styles-array.ts @@ -40,10 +40,10 @@ export default function () { .then(() => expectFileToMatch('dist/common-entry.bundle.css', '.common-entry-style')) .then(() => expectFileToMatch('dist/common-entry.bundle.js', 'common-entry-script')) // there are no js entry points for css only bundles - .then(() => expectToFail(() => expectFileToExist('dist/styles.bundle.js'))) - .then(() => expectToFail(() => expectFileToExist('dist/lazy-styles.bundle.js'))) - .then(() => expectToFail(() => expectFileToExist('dist/renamed-styles.bundle.js'))) - .then(() => expectToFail(() => expectFileToExist('dist/renamed-lazy-styles.bundle.js'))) + .then(() => expectToFail(() => expectFileToExist('dist/style.bundle.js'))) + .then(() => expectToFail(() => expectFileToExist('dist/lazy-style.bundle.js'))) + .then(() => expectToFail(() => expectFileToExist('dist/renamed-style.bundle.js'))) + .then(() => expectToFail(() => expectFileToExist('dist/renamed-lazy-style.bundle.js'))) // index.html lists the right bundles .then(() => expectFileToMatch('dist/index.html', oneLineTrim` @@ -55,5 +55,11 @@ export default function () { - `)); + `)) + .then(() => ng('build', '--no-extract-css')) + // js files still exist when not extracting css + .then(() => expectFileToExist('dist/styles.bundle.js')) + .then(() => expectFileToExist('dist/lazy-style.bundle.js')) + .then(() => expectFileToExist('dist/renamed-style.bundle.js')) + .then(() => expectFileToExist('dist/renamed-lazy-style.bundle.js')); }