diff --git a/e2e/react/src/react.test.ts b/e2e/react/src/react.test.ts index 78af47b06d..7979626f0d 100644 --- a/e2e/react/src/react.test.ts +++ b/e2e/react/src/react.test.ts @@ -1,4 +1,3 @@ -import { serializeJson } from '@nrwl/workspace'; import { checkFilesDoNotExist, checkFilesExist, @@ -42,20 +41,19 @@ describe('React Applications', () => { await testGeneratedApp(appName, { checkStyles: true, - checkProdBuild: true, checkLinter: true, checkE2E: true, }); }, 500000); - it('should support vendor sourcemaps', () => { + it('should support sourcemaps', () => { const appName = uniq('app'); runCLI(`generate @nrwl/react:app ${appName} --no-interactive`); - runCLI(`build ${appName} --sourceMap`); + runCLI(`build ${appName} --sourceMap --outputHashing none`); - checkFilesExist(`dist/apps/${appName}/vendor.js.map`); + checkFilesExist(`dist/apps/${appName}/main.esm.js.map`); }, 250000); it('should be able to generate a publishable react lib', async () => { @@ -114,7 +112,6 @@ describe('React Applications', () => { await testGeneratedApp(appName, { checkStyles: true, - checkProdBuild: false, checkLinter: false, checkE2E: false, }); @@ -145,7 +142,6 @@ describe('React Applications', () => { await testGeneratedApp(appName, { checkStyles: true, - checkProdBuild: false, checkLinter: false, checkE2E: false, }); @@ -185,18 +181,10 @@ describe('React Applications', () => { await testGeneratedApp(styledComponentsApp, { checkStyles: false, - checkProdBuild: true, checkLinter: false, checkE2E: false, }); - expect(readFile(`dist/apps/${styledComponentsApp}/main.js`)).toContain( - 'app__StyledApp' - ); - expect( - readFile(`dist/apps/${styledComponentsApp}/prod/main.esm.js`) - ).not.toContain('app__StyledApp'); - const styledJsxApp = uniq('app'); runCLI( @@ -205,7 +193,6 @@ describe('React Applications', () => { await testGeneratedApp(styledJsxApp, { checkStyles: false, - checkProdBuild: false, checkLinter: false, checkE2E: false, }); @@ -218,7 +205,6 @@ describe('React Applications', () => { await testGeneratedApp(noStylesApp, { checkStyles: false, - checkProdBuild: false, checkLinter: false, checkE2E: false, }); @@ -236,24 +222,23 @@ describe('React Applications', () => { runCLI(`generate @nrwl/react:app ${appName} --style=css --no-interactive`); - // changing browser suporrt of this application + // changing browser support of this application updateFile(`apps/${appName}/.browserslistrc`, `IE 11`); await testGeneratedApp(appName, { checkStyles: false, - checkProdBuild: true, checkLinter: false, checkE2E: false, }); const filesToCheck = [ - `dist/apps/${appName}/prod/polyfills.es5.js`, - `dist/apps/${appName}/prod/main.es5.js`, + `dist/apps/${appName}/polyfills.es5.js`, + `dist/apps/${appName}/main.es5.js`, ]; checkFilesExist(...filesToCheck); - expect(readFile(`dist/apps/${appName}/prod/index.html`)).toContain( + expect(readFile(`dist/apps/${appName}/index.html`)).toContain( `` ); }, 250000); @@ -312,7 +297,6 @@ describe('React Applications', () => { await testGeneratedApp(appName, { checkStyles: true, - checkProdBuild: false, checkLinter: false, checkE2E: false, }); @@ -321,7 +305,6 @@ describe('React Applications', () => { async function testGeneratedApp( appName, opts: { - checkProdBuild: boolean; checkStyles: boolean; checkLinter: boolean; checkE2E: boolean; @@ -332,44 +315,22 @@ describe('React Applications', () => { expect(lintResults).toContain('All files pass linting.'); } - runCLI(`build ${appName}`); - let filesToCheck = [ + runCLI(`build ${appName} --outputHashing none`); + const filesToCheck = [ `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/polyfills.js`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/vendor.js`, - `dist/apps/${appName}/main.js`, + `dist/apps/${appName}/runtime.esm.js`, + `dist/apps/${appName}/polyfills.esm.js`, + `dist/apps/${appName}/main.esm.js`, ]; if (opts.checkStyles) { - filesToCheck.push(`dist/apps/${appName}/styles.js`); + filesToCheck.push(`dist/apps/${appName}/styles.css`); } checkFilesExist(...filesToCheck); - expect(readFile(`dist/apps/${appName}/main.js`)).toContain( - 'function App() {' - ); - - if (opts.checkProdBuild) { - const prodOutputPath = `dist/apps/${appName}/prod`; - runCLI( - `build ${appName} --prod --output-hashing none --outputPath ${prodOutputPath}` + if (opts.checkStyles) { + expect(readFile(`dist/apps/${appName}/index.html`)).toContain( + `` ); - filesToCheck = [ - `${prodOutputPath}/index.html`, - `${prodOutputPath}/runtime.esm.js`, - `${prodOutputPath}/polyfills.esm.js`, - `${prodOutputPath}/main.esm.js`, - ]; - if (opts.checkStyles) { - filesToCheck.push(`${prodOutputPath}/styles.css`); - } - checkFilesExist(...filesToCheck); - - if (opts.checkStyles) { - expect(readFile(`${prodOutputPath}/index.html`)).toContain( - `` - ); - } } const testResults = await runCLIAsync(`test ${appName}`); @@ -385,7 +346,7 @@ describe('React Applications', () => { } }); -describe('--style option', () => { +fdescribe('--style option', () => { beforeAll(() => newProject()); it.each` @@ -420,11 +381,7 @@ describe('--style option', () => { `body { font-family: "Comic Sans MS"; }` ); - runCLI(`build ${appName}`); - - expect(readFile(`dist/apps/${appName}/styles.js`)).toMatch(/Comic Sans MS/); - - runCLI(`build ${appName} --prod --output-hashing none`); + runCLI(`build ${appName} --outputHashing none`); expect(readFile(`dist/apps/${appName}/styles.css`)).toMatch( /Comic Sans MS/ diff --git a/e2e/web/src/web.test.ts b/e2e/web/src/web.test.ts index bdbab24f68..b8e55a8723 100644 --- a/e2e/web/src/web.test.ts +++ b/e2e/web/src/web.test.ts @@ -24,20 +24,7 @@ describe('Web Components Applications', () => { const lintResults = runCLI(`lint ${appName}`); expect(lintResults).toContain('All files pass linting.'); - runCLI(`build ${appName}`); - checkFilesExist( - `dist/apps/${appName}/index.html`, - `dist/apps/${appName}/runtime.js`, - `dist/apps/${appName}/polyfills.js`, - `dist/apps/${appName}/main.js`, - `dist/apps/${appName}/styles.js` - ); - - expect(readFile(`dist/apps/${appName}/main.js`)).toContain( - 'class AppElement' - ); - - runCLI(`build ${appName} --prod --output-hashing none`); + runCLI(`build ${appName} --outputHashing none`); checkFilesExist( `dist/apps/${appName}/index.html`, `dist/apps/${appName}/runtime.esm.js`, @@ -93,7 +80,7 @@ describe('Web Components Applications', () => { `dist/apps/${appName}/_should_remove.txt`, `dist/apps/_should_not_remove.txt` ); - runCLI(`build ${appName}`); + runCLI(`build ${appName} --outputHashing none`); runCLI(`build ${libName}`); checkFilesDoNotExist( `dist/apps/${appName}/_should_remove.txt`, @@ -103,11 +90,11 @@ describe('Web Components Applications', () => { // `delete-output-path` createFile(`dist/apps/${appName}/_should_keep.txt`); - runCLI(`build ${appName} --delete-output-path=false`); + runCLI(`build ${appName} --delete-output-path=false --outputHashing none`); checkFilesExist(`dist/apps/${appName}/_should_keep.txt`); createFile(`dist/libs/${libName}/_should_keep.txt`); - runCLI(`build ${libName} --delete-output-path=false`); + runCLI(`build ${libName} --delete-output-path=false --outputHashing none`); checkFilesExist(`dist/libs/${libName}/_should_keep.txt`); }, 120000); @@ -118,7 +105,7 @@ describe('Web Components Applications', () => { updateFile(`apps/${appName}/browserslist`, `IE 9-11`); - runCLI(`build ${appName} --prod --outputHashing=none`); + runCLI(`build ${appName} --outputHashing=none`); checkFilesExist( `dist/apps/${appName}/main.esm.js`, @@ -159,9 +146,9 @@ describe('Web Components Applications', () => { `; return newContent; }); - runCLI(`build ${appName}`); + runCLI(`build ${appName} --outputHashing none`); - expect(readFile(`dist/apps/${appName}/main.js`)).toMatch( + expect(readFile(`dist/apps/${appName}/main.esm.js`)).toMatch( /Reflect\.metadata/ ); @@ -172,9 +159,9 @@ describe('Web Components Applications', () => { return JSON.stringify(json); }); - runCLI(`build ${appName}`); + runCLI(`build ${appName} --outputHashing none`); - expect(readFile(`dist/apps/${appName}/main.js`)).not.toMatch( + expect(readFile(`dist/apps/${appName}/main.esm.js`)).not.toMatch( /Reflect\.metadata/ ); }, 120000); @@ -254,7 +241,7 @@ describe('CLI - Environment Variables', () => { updateFile(main2, `${newCode2}\n${content2}`); - runCLI(`run-many --target=build --all`, { + runCLI(`run-many --target build --all --no-optimization`, { env: { ...process.env, NODE_ENV: 'test', @@ -332,13 +319,13 @@ describe('Build Options', () => { return config; }); - runCLI(`build ${appName}`); + runCLI(`build ${appName} --outputHashing none --optimization false`); const distPath = `dist/apps/${appName}`; const scripts = readFile(`${distPath}/scripts.js`); - const styles = readFile(`${distPath}/styles.js`); + const styles = readFile(`${distPath}/styles.css`); const barScripts = readFile(`${distPath}/${barScriptsBundleName}.js`); - const barStyles = readFile(`${distPath}/${barStylesBundleName}.js`); + const barStyles = readFile(`${distPath}/${barStylesBundleName}.css`); expect(scripts).toContain(fooJsContent); expect(scripts).not.toContain(barJsContent); diff --git a/e2e/workspace-integrations/src/workspace.test.ts b/e2e/workspace-integrations/src/workspace.test.ts index 75862101e8..bd739d2b65 100644 --- a/e2e/workspace-integrations/src/workspace.test.ts +++ b/e2e/workspace-integrations/src/workspace.test.ts @@ -7,7 +7,6 @@ import { readFile, readJson, readProjectConfig, - readWorkspaceConfig, removeProject, rmDist, runCLI, @@ -669,13 +668,13 @@ describe('print-affected', () => { ); expect(resWithDeps.tasks[0]).toMatchObject({ - id: `${myapp}:build`, + id: `${myapp}:build:production`, overrides: {}, target: { project: myapp, target: 'build', }, - command: `${runNx} build ${myapp}`, + command: `${runNx} build ${myapp} --configuration production`, outputs: [`dist/apps/${myapp}`], }); diff --git a/package.json b/package.json index 81c51f3cd3..f687ff48f9 100644 --- a/package.json +++ b/package.json @@ -222,7 +222,7 @@ "strip-json-comments": "^3.1.1", "style-loader": "^3.3.0", "styled-components": "5.0.0", - "stylus": "0.54.5", + "stylus": "^0.55.0", "stylus-loader": "^6.2.0", "tailwindcss": "^2.2.17", "tcp-port-used": "^1.0.2", diff --git a/packages/next/src/generators/application/lib/add-project.ts b/packages/next/src/generators/application/lib/add-project.ts index 3821df2501..0dcef2a6f0 100644 --- a/packages/next/src/generators/application/lib/add-project.ts +++ b/packages/next/src/generators/application/lib/add-project.ts @@ -12,6 +12,7 @@ export function addProject(host: Tree, options: NormalizedSchema) { targets.build = { builder: '@nrwl/next:build', outputs: ['{options.outputPath}'], + defaultConfiguration: 'production', options: { root: options.appProjectRoot, outputPath: joinPathFragments('dist', options.appProjectRoot), diff --git a/packages/react/plugins/webpack.ts b/packages/react/plugins/webpack.ts index aae856c4ac..8e1dbaa143 100644 --- a/packages/react/plugins/webpack.ts +++ b/packages/react/plugins/webpack.ts @@ -58,8 +58,7 @@ function getWebpackConfig(config: Configuration) { const babelLoader = config.module.rules.find( (rule) => typeof rule !== 'string' && - rule.loader && - rule.loader.toString().includes('babel-loader') + rule.loader?.toString().includes('babel-loader') ); if (babelLoader && typeof babelLoader !== 'string') { babelLoader.options['plugins'] = [ diff --git a/packages/react/src/generators/application/application.spec.ts b/packages/react/src/generators/application/application.spec.ts index 662bfa0c8f..dd1585ddfd 100644 --- a/packages/react/src/generators/application/application.spec.ts +++ b/packages/react/src/generators/application/application.spec.ts @@ -263,7 +263,6 @@ Object { }); expect(targetConfig.build.configurations.production).toEqual({ optimization: true, - extractCss: true, extractLicenses: true, fileReplacements: [ { diff --git a/packages/react/src/generators/application/lib/add-project.ts b/packages/react/src/generators/application/lib/add-project.ts index 302e3485c3..a1888180b4 100644 --- a/packages/react/src/generators/application/lib/add-project.ts +++ b/packages/react/src/generators/application/lib/add-project.ts @@ -1,7 +1,7 @@ import { NormalizedSchema } from '../schema'; import { - joinPathFragments, addProjectConfiguration, + joinPathFragments, ProjectConfiguration, TargetConfiguration, } from '@nrwl/devkit'; @@ -38,6 +38,7 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration { return { executor: '@nrwl/web:build', outputs: ['{options.outputPath}'], + defaultConfiguration: 'production', options: { outputPath: joinPathFragments('dist', options.appProjectRoot), index: joinPathFragments(options.appProjectRoot, 'src/index.html'), @@ -84,7 +85,6 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration { optimization: true, outputHashing: 'all', sourceMap: false, - extractCss: true, namedChunks: false, extractLicenses: true, vendorChunk: false, diff --git a/packages/web/package.json b/packages/web/package.json index 740c724abf..c57900d1e9 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -95,7 +95,7 @@ "source-map": "0.7.3", "source-map-loader": "^3.0.0", "style-loader": "^3.3.0", - "stylus": "0.54.5", + "stylus": "^0.55.0", "stylus-loader": "^6.2.0", "terser": "4.3.8", "terser-webpack-plugin": "^5.1.1", diff --git a/packages/web/src/executors/build/build.impl.ts b/packages/web/src/executors/build/build.impl.ts index a1c53ff7d1..6b7fdd306e 100644 --- a/packages/web/src/executors/build/build.impl.ts +++ b/packages/web/src/executors/build/build.impl.ts @@ -15,24 +15,24 @@ import { } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; -import { writeIndexHtml } from '../../utils/third-party/cli-files/utilities/index-file/write-index-html'; -import { CrossOriginValue } from '../../utils/third-party/cli-files/utilities/index-file/augment-index-html'; -import { BuildBrowserFeatures } from '../../utils/third-party/utils/build-browser-features'; - import { normalizeWebBuildOptions } from '../../utils/normalize'; import { getWebConfig } from '../../utils/web.config'; -import type { BuildBuilderOptions } from '../../utils/types'; -import { deleteOutputDir } from '../../utils/delete-output-dir'; -import type { ExtraEntryPoint } from '../../utils/third-party/browser/schema'; +import type { BuildBuilderOptions } from '../../utils/shared-models'; +import { ExtraEntryPoint } from '../../utils/shared-models'; import { getEmittedFiles, runWebpack } from '../../utils/run-webpack'; +import { BuildBrowserFeatures } from '../../utils/webpack/build-browser-features'; +import { deleteOutputDir } from '../../utils/fs'; +import { + CrossOriginValue, + writeIndexHtml, +} from '../../utils/webpack/write-index-html'; -export interface WebBuildBuilderOptions extends BuildBuilderOptions { +export interface WebBuildExecutorOptions extends BuildBuilderOptions { index: string; budgets?: any[]; baseHref?: string; deployUrl?: string; - extractCss?: boolean; crossOrigin?: CrossOriginValue; polyfills?: string; @@ -58,7 +58,7 @@ export interface WebBuildBuilderOptions extends BuildBuilderOptions { } function getWebpackConfigs( - options: WebBuildBuilderOptions, + options: WebBuildExecutorOptions, context: ExecutorContext ): Configuration[] { const metadata = context.workspace.projects[context.projectName]; @@ -115,7 +115,7 @@ function getWebpackConfigs( } export async function* run( - options: WebBuildBuilderOptions, + options: WebBuildExecutorOptions, context: ExecutorContext ) { // Node versions 12.2-12.8 has a bug where prod builds will hang for 2-3 minutes diff --git a/packages/web/src/executors/dev-server/dev-server.impl.ts b/packages/web/src/executors/dev-server/dev-server.impl.ts index 8a7a3e2f92..b0975b819e 100644 --- a/packages/web/src/executors/dev-server/dev-server.impl.ts +++ b/packages/web/src/executors/dev-server/dev-server.impl.ts @@ -11,7 +11,7 @@ import { map, tap } from 'rxjs/operators'; import * as WebpackDevServer from 'webpack-dev-server'; import { normalizeWebBuildOptions } from '../../utils/normalize'; -import { WebBuildBuilderOptions } from '../build/build.impl'; +import { WebBuildExecutorOptions } from '../build/build.impl'; import { getDevServerConfig } from '../../utils/devserver.config'; import { calculateProjectDependencies, @@ -100,9 +100,9 @@ export default async function* devServerExecutor( function getBuildOptions( options: WebDevServerOptions, context: ExecutorContext -): WebBuildBuilderOptions { +): WebBuildExecutorOptions { const target = parseTargetString(options.buildTarget); - const overrides: Partial = { + const overrides: Partial = { watch: false, }; if (options.maxWorkers) { diff --git a/packages/web/src/executors/package/lib/normalize.ts b/packages/web/src/executors/package/lib/normalize.ts index e495ca4ba5..e457582b1c 100644 --- a/packages/web/src/executors/package/lib/normalize.ts +++ b/packages/web/src/executors/package/lib/normalize.ts @@ -1,6 +1,6 @@ import { dirname } from 'path'; -import { AssetGlobPattern } from '../../../utils/types'; +import { AssetGlobPattern } from '../../../utils/shared-models'; import { normalizeAssets, normalizePluginPath } from '../../../utils/normalize'; import { WebPackageOptions } from '../schema'; diff --git a/packages/web/src/executors/package/package.impl.ts b/packages/web/src/executors/package/package.impl.ts index 000a6e95d5..d5c82cfeaf 100644 --- a/packages/web/src/executors/package/package.impl.ts +++ b/packages/web/src/executors/package/package.impl.ts @@ -19,8 +19,7 @@ import { } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; import resolve from '@rollup/plugin-node-resolve'; -import { AssetGlobPattern } from '../../utils/types'; -import { deleteOutputDir } from '../../utils/delete-output-dir'; +import { AssetGlobPattern } from '../../utils/shared-models'; import { WebPackageOptions } from './schema'; import { runRollup } from './lib/run-rollup'; import { @@ -28,6 +27,7 @@ import { normalizePackageOptions, } from './lib/normalize'; import { analyze } from './lib/analyze-plugin'; +import { deleteOutputDir } from '../../utils/fs'; // These use require because the ES import isn't correct. const commonjs = require('@rollup/plugin-commonjs'); diff --git a/packages/web/src/generators/application/application.spec.ts b/packages/web/src/generators/application/application.spec.ts index ea40c974d5..e5aec4c651 100644 --- a/packages/web/src/generators/application/application.spec.ts +++ b/packages/web/src/generators/application/application.spec.ts @@ -269,7 +269,6 @@ describe('app', () => { }); expect(architectConfig.build.configurations.production).toEqual({ optimization: true, - extractCss: true, extractLicenses: true, fileReplacements: [ { diff --git a/packages/web/src/generators/application/application.ts b/packages/web/src/generators/application/application.ts index 63cd76729b..2db8405f75 100644 --- a/packages/web/src/generators/application/application.ts +++ b/packages/web/src/generators/application/application.ts @@ -23,7 +23,7 @@ import { cypressProjectGenerator } from '@nrwl/cypress'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { jestProjectGenerator } from '@nrwl/jest'; -import { WebBuildBuilderOptions } from '../../executors/build/build.impl'; +import { WebBuildExecutorOptions } from '../../executors/build/build.impl'; import { Schema } from './schema'; interface NormalizedSchema extends Schema { @@ -50,7 +50,7 @@ function addBuildTarget( project: ProjectConfiguration, options: NormalizedSchema ): ProjectConfiguration { - const buildOptions: WebBuildBuilderOptions = { + const buildOptions: WebBuildExecutorOptions = { outputPath: joinPathFragments('dist', options.appProjectRoot), index: joinPathFragments(options.appProjectRoot, 'src/index.html'), baseHref: '/', @@ -66,7 +66,7 @@ function addBuildTarget( ], scripts: [], }; - const productionBuildOptions: Partial = { + const productionBuildOptions: Partial = { fileReplacements: [ { replace: joinPathFragments( @@ -82,7 +82,6 @@ function addBuildTarget( optimization: true, outputHashing: 'all', sourceMap: false, - extractCss: true, namedChunks: false, extractLicenses: true, vendorChunk: false, @@ -95,6 +94,7 @@ function addBuildTarget( build: { executor: '@nrwl/web:build', outputs: ['{options.outputPath}'], + defaultConfiguration: 'production', options: buildOptions, configurations: { production: productionBuildOptions, diff --git a/packages/web/src/utils/config.ts b/packages/web/src/utils/config.ts index ad2dd97a50..aad815ad32 100644 --- a/packages/web/src/utils/config.ts +++ b/packages/web/src/utils/config.ts @@ -4,7 +4,7 @@ import { Configuration, WebpackPluginInstance } from 'webpack'; import { LicenseWebpackPlugin } from 'license-webpack-plugin'; import * as CopyWebpackPlugin from 'copy-webpack-plugin'; import * as TerserWebpackPlugin from 'terser-webpack-plugin'; -import { AssetGlobPattern, BuildBuilderOptions } from './types'; +import { AssetGlobPattern, BuildBuilderOptions } from './shared-models'; import { getOutputHashFormat } from './hash-format'; // Inlining tsconfig-paths-webpack-plugin with a patch diff --git a/packages/web/src/utils/delete-output-dir.ts b/packages/web/src/utils/delete-output-dir.ts deleted file mode 100644 index 7185d0ee3b..0000000000 --- a/packages/web/src/utils/delete-output-dir.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { resolve } from 'path'; -import { removeSync } from 'fs-extra'; - -/** - * Delete an output directory, but error out if it's the root of the project. - */ -export function deleteOutputDir(root: string, outputPath: string) { - const resolvedOutputPath = resolve(root, outputPath); - if (resolvedOutputPath === root) { - throw new Error('Output path MUST not be project root directory!'); - } - - removeSync(resolvedOutputPath); -} diff --git a/packages/web/src/utils/devserver.config.ts b/packages/web/src/utils/devserver.config.ts index 8fc2d43e42..c5bea67160 100644 --- a/packages/web/src/utils/devserver.config.ts +++ b/packages/web/src/utils/devserver.config.ts @@ -3,17 +3,17 @@ import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-serv import * as path from 'path'; import { getWebConfig } from './web.config'; -import { WebBuildBuilderOptions } from '../executors/build/build.impl'; +import { WebBuildExecutorOptions } from '../executors/build/build.impl'; import { WebDevServerOptions } from '../executors/dev-server/dev-server.impl'; import { buildServePath } from './serve-path'; -import { OptimizationOptions } from './types'; +import { OptimizationOptions } from './shared-models'; import { readFileSync } from 'fs-extra'; export function getDevServerConfig( workspaceRoot: string, projectRoot: string, sourceRoot: string, - buildOptions: WebBuildBuilderOptions, + buildOptions: WebBuildExecutorOptions, serveOptions: WebDevServerOptions ): Partial { const webpackConfig = getWebConfig( @@ -37,7 +37,7 @@ export function getDevServerConfig( function getDevServerPartial( root: string, options: WebDevServerOptions, - buildOptions: WebBuildBuilderOptions + buildOptions: WebBuildExecutorOptions ): WebpackDevServerConfiguration { const servePath = buildServePath(buildOptions); @@ -49,7 +49,7 @@ function getDevServerPartial( port: options.port, headers: { 'Access-Control-Allow-Origin': '*' }, historyApiFallback: { - index: `${servePath}/${path.basename(buildOptions.index)}`, + index: `${servePath}${path.basename(buildOptions.index)}`, disableDotRule: true, htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], }, diff --git a/packages/web/src/utils/third-party/cli-files/utilities/find-up.ts b/packages/web/src/utils/fs.ts similarity index 67% rename from packages/web/src/utils/third-party/cli-files/utilities/find-up.ts rename to packages/web/src/utils/fs.ts index e207f632c8..86762162d3 100644 --- a/packages/web/src/utils/third-party/cli-files/utilities/find-up.ts +++ b/packages/web/src/utils/fs.ts @@ -1,13 +1,5 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { existsSync } from 'fs'; import * as path from 'path'; -import { isDirectory } from './is-directory'; +import { existsSync, removeSync, statSync } from 'fs-extra'; export function findUp( names: string | string[], @@ -60,3 +52,23 @@ export function findAllNodeModules(from: string, root?: string) { return nodeModules; } + +/** + * Delete an output directory, but error out if it's the root of the project. + */ +export function deleteOutputDir(root: string, outputPath: string) { + const resolvedOutputPath = path.resolve(root, outputPath); + if (resolvedOutputPath === root) { + throw new Error('Output path MUST not be project root directory!'); + } + + removeSync(resolvedOutputPath); +} + +export function isDirectory(path: string) { + try { + return statSync(path).isDirectory(); + } catch (_) { + return false; + } +} diff --git a/packages/web/src/utils/hash-format.ts b/packages/web/src/utils/hash-format.ts index 2015cc42b7..f3693f67d1 100644 --- a/packages/web/src/utils/hash-format.ts +++ b/packages/web/src/utils/hash-format.ts @@ -1,5 +1,3 @@ -// Originally from devkit. -// See: https://github.com/angular/angular-cli/blob/2c8b12f/packages/angular_devkit/build_angular/src/angular-cli-files/models/webpack-configs/utils.ts export interface HashFormat { chunk: string; extract: string; diff --git a/packages/web/src/utils/normalize.spec.ts b/packages/web/src/utils/normalize.spec.ts index 456d022836..57b4d8b57f 100644 --- a/packages/web/src/utils/normalize.spec.ts +++ b/packages/web/src/utils/normalize.spec.ts @@ -1,5 +1,5 @@ import { normalizeBuildOptions } from './normalize'; -import { BuildBuilderOptions } from './types'; +import { BuildBuilderOptions } from './shared-models'; import * as fs from 'fs'; diff --git a/packages/web/src/utils/normalize.ts b/packages/web/src/utils/normalize.ts index 87a8c06c2e..e33c651a0d 100644 --- a/packages/web/src/utils/normalize.ts +++ b/packages/web/src/utils/normalize.ts @@ -1,7 +1,12 @@ -import { WebBuildBuilderOptions } from '../executors/build/build.impl'; +import { WebBuildExecutorOptions } from '../executors/build/build.impl'; import { normalizePath } from '@nrwl/devkit'; import { basename, dirname, relative, resolve } from 'path'; -import { AssetGlobPattern, BuildBuilderOptions } from './types'; +import { + AssetGlobPattern, + BuildBuilderOptions, + ExtraEntryPoint, + ExtraEntryPointClass, +} from './shared-models'; import { statSync } from 'fs'; export interface FileReplacement { @@ -96,10 +101,10 @@ function normalizeFileReplacements( } export function normalizeWebBuildOptions( - options: WebBuildBuilderOptions, + options: WebBuildExecutorOptions, root: string, sourceRoot: string -): WebBuildBuilderOptions { +): WebBuildExecutorOptions { return { ...normalizeBuildOptions(options, root, sourceRoot), optimization: @@ -116,7 +121,9 @@ export function normalizeWebBuildOptions( }; } -export function convertBuildOptions(buildOptions: WebBuildBuilderOptions): any { +export function convertBuildOptions( + buildOptions: WebBuildExecutorOptions +): any { const options = buildOptions as any; return { ...options, @@ -125,3 +132,42 @@ export function convertBuildOptions(buildOptions: WebBuildBuilderOptions): any { lazyModules: [] as string[], }; } + +export type NormalizedEntryPoint = Required>; + +export function normalizeExtraEntryPoints( + extraEntryPoints: ExtraEntryPoint[], + defaultBundleName: string +): NormalizedEntryPoint[] { + return extraEntryPoints.map((entry) => { + let normalizedEntry; + if (typeof entry === 'string') { + normalizedEntry = { + input: entry, + inject: true, + bundleName: defaultBundleName, + }; + } else { + const { lazy, inject = true, ...newEntry } = entry; + const injectNormalized = entry.lazy !== undefined ? !entry.lazy : inject; + let bundleName; + + if (entry.bundleName) { + bundleName = entry.bundleName; + } else if (!injectNormalized) { + // Lazy entry points use the file name as bundle name. + bundleName = basename( + normalizePath( + entry.input.replace(/\.(js|css|scss|sass|less|styl)$/i, '') + ) + ); + } else { + bundleName = defaultBundleName; + } + + normalizedEntry = { ...newEntry, inject: injectNormalized, bundleName }; + } + + return normalizedEntry; + }); +} diff --git a/packages/web/src/utils/serve-path.ts b/packages/web/src/utils/serve-path.ts index e94b349ba7..8be2c9eff3 100644 --- a/packages/web/src/utils/serve-path.ts +++ b/packages/web/src/utils/serve-path.ts @@ -1,6 +1,6 @@ -import { WebBuildBuilderOptions } from '../executors/build/build.impl'; +import { WebBuildExecutorOptions } from '../executors/build/build.impl'; -export function buildServePath(browserOptions: WebBuildBuilderOptions) { +export function buildServePath(browserOptions: WebBuildExecutorOptions) { let servePath = _findDefaultServePath(browserOptions.baseHref, browserOptions.deployUrl) || '/'; diff --git a/packages/web/src/utils/shared-models.ts b/packages/web/src/utils/shared-models.ts new file mode 100644 index 0000000000..cbb7aa8990 --- /dev/null +++ b/packages/web/src/utils/shared-models.ts @@ -0,0 +1,120 @@ +import { WebBuildExecutorOptions } from '../executors/build/build.impl'; +import { FileReplacement } from './normalize'; + +export interface OptimizationOptions { + scripts: boolean; + styles: boolean; +} + +export interface BuildBuilderOptions { + main: string; + outputPath: string; + tsConfig: string; + watch?: boolean; + sourceMap?: boolean | 'hidden'; + optimization?: boolean | OptimizationOptions; + memoryLimit?: number; + maxWorkers?: number; + poll?: number; + + fileReplacements?: FileReplacement[]; + assets?: any[]; + + progress?: boolean; + statsJson?: boolean; + extractLicenses?: boolean; + verbose?: boolean; + + outputHashing?: any; + webpackConfig?: string; + + root?: string; + sourceRoot?: string; +} + +export interface AssetGlobPattern { + glob: string; + input: string; + output: string; + ignore?: string[]; +} + +export type AssetPattern = AssetPatternClass | string; + +export interface AssetPatternClass { + glob: string; + ignore?: string[]; + input: string; + output: string; +} + +export enum Type { + All = 'all', + AllScript = 'allScript', + Any = 'any', + AnyComponentStyle = 'anyComponentStyle', + AnyScript = 'anyScript', + Bundle = 'bundle', + Initial = 'initial', +} + +export enum CrossOrigin { + Anonymous = 'anonymous', + None = 'none', + UseCredentials = 'use-credentials', +} + +export type IndexUnion = IndexObject | string; + +export interface IndexObject { + input: string; + output?: string; +} + +export type Localize = string[] | boolean; + +export type OptimizationUnion = boolean | OptimizationClass; + +export interface OptimizationClass { + scripts?: boolean; + styles?: boolean; +} + +export enum OutputHashing { + All = 'all', + Bundles = 'bundles', + Media = 'media', + None = 'none', +} + +export type ExtraEntryPoint = ExtraEntryPointClass | string; + +export interface ExtraEntryPointClass { + bundleName?: string; + inject?: boolean; + input: string; + lazy?: boolean; +} + +export type SourceMapUnion = boolean | SourceMapClass; + +export interface SourceMapClass { + hidden?: boolean; + scripts?: boolean; + styles?: boolean; + vendor?: boolean; +} + +export interface StylePreprocessorOptions { + includePaths?: string[]; +} + +export interface WebpackConfigOptions { + root: string; + projectRoot: string; + sourceRoot?: string; + buildOptions: T; + tsConfig: any; + tsConfigPath: string; + supportES2015: boolean; +} diff --git a/packages/web/src/utils/third-party/browser/schema.ts b/packages/web/src/utils/third-party/browser/schema.ts deleted file mode 100644 index 30f13571ff..0000000000 --- a/packages/web/src/utils/third-party/browser/schema.ts +++ /dev/null @@ -1,425 +0,0 @@ -// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE -// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...). - -// tslint:disable:no-global-tslint-disable -// tslint:disable - -/** - * Browser target options - */ -export interface Schema { - /** - * Build using Ahead of Time compilation. - */ - aot?: boolean; - /** - * List of static application assets. - */ - assets?: AssetPattern[]; - /** - * Base url for the application being built. - */ - baseHref?: string; - /** - * Budget thresholds to ensure parts of your application stay within boundaries which you - * set. - */ - budgets?: Budget[]; - /** - * Enables '@angular-devkit/build-optimizer' optimizations when using the 'aot' option. - */ - buildOptimizer?: boolean; - /** - * Use a separate bundle containing code used across multiple bundles. - */ - commonChunk?: boolean; - /** - * Define the crossorigin attribute setting of elements that provide CORS support. - */ - crossOrigin?: CrossOrigin; - /** - * Delete the output path before building. - */ - deleteOutputPath?: boolean; - /** - * URL where files will be deployed. - */ - deployUrl?: string; - /** - * Enables conditionally loaded ES2015 polyfills. - * @deprecated This will be determined from the list of supported browsers specified in the - * 'browserslist' file. - */ - es5BrowserSupport?: boolean; - /** - * Output in-file eval sourcemaps. - * @deprecated - */ - evalSourceMap?: boolean; - /** - * Concatenate modules with Rollup before bundling them with Webpack. - */ - experimentalRollupPass?: boolean; - /** - * Extract css from global styles into css files instead of js ones. - */ - extractCss?: boolean; - /** - * Extract all licenses in a separate file. - */ - extractLicenses?: boolean; - /** - * Replace files with other files in the build. - */ - fileReplacements?: FileReplacement[]; - /** - * Run the TypeScript type checker in a forked process. - */ - forkTypeChecker?: boolean; - /** - * Localization file to use for i18n. - * @deprecated Use 'locales' object in the project metadata instead. - */ - i18nFile?: string; - /** - * Format of the localization file specified with --i18n-file. - * @deprecated No longer needed as the format will be determined automatically. - */ - i18nFormat?: string; - /** - * Locale to use for i18n. - * @deprecated Use 'localize' instead. - */ - i18nLocale?: string; - /** - * How to handle missing translations for i18n. - */ - i18nMissingTranslation?: I18NMissingTranslation; - /** - * Configures the generation of the application's HTML index. - */ - index: IndexUnion; - /** - * List of additional NgModule files that will be lazy loaded. Lazy router modules will be - * discovered automatically. - * @deprecated 'SystemJsNgModuleLoader' is deprecated, and this is part of its usage. Use - * 'import()' syntax instead. - */ - lazyModules?: string[]; - localize?: Localize; - /** - * The full path for the main entry point to the app, relative to the current workspace. - */ - main: string; - /** - * Use file name for lazy loaded chunks. - */ - namedChunks?: boolean; - /** - * Path to ngsw-config.json. - */ - ngswConfigPath?: string; - /** - * Enables optimization of the build output. - */ - optimization?: OptimizationUnion; - /** - * Define the output filename cache-busting hashing mode. - */ - outputHashing?: OutputHashing; - /** - * The full path for the new output directory, relative to the current workspace. - * - * By default, writes output to a folder named dist/ in the current project. - */ - outputPath: string; - /** - * Enable and define the file watching poll time period in milliseconds. - */ - poll?: number; - /** - * The full path for the polyfills file, relative to the current workspace. - */ - polyfills?: string; - /** - * Do not use the real path when resolving modules. - */ - preserveSymlinks?: boolean; - /** - * Output profile events for Chrome profiler. - * @deprecated Use "NG_BUILD_PROFILING" environment variable instead. - */ - profile?: boolean; - /** - * Log progress to the console while building. - */ - progress?: boolean; - /** - * Change root relative URLs in stylesheets to include base HREF and deploy URL. Use only - * for compatibility and transition. The behavior of this option is non-standard and will be - * removed in the next major release. - * @deprecated - */ - rebaseRootRelativeCssUrls?: boolean; - /** - * The path where style resources will be placed, relative to outputPath. - */ - resourcesOutputPath?: string; - /** - * Global scripts to be included in the build. - */ - scripts?: ExtraEntryPoint[]; - /** - * Generates a service worker config for production builds. - */ - serviceWorker?: boolean; - /** - * Flag to prevent building an app shell. - * @deprecated - */ - skipAppShell?: boolean; - /** - * Output sourcemaps. - */ - sourceMap?: SourceMapUnion; - /** - * Generates a 'stats.json' file which can be analyzed using tools such as - * 'webpack-bundle-analyzer'. - */ - statsJson?: boolean; - /** - * Options to pass to style preprocessors. - */ - stylePreprocessorOptions?: StylePreprocessorOptions; - /** - * Global styles to be included in the build. - */ - styles?: ExtraEntryPoint[]; - /** - * Enables the use of subresource integrity validation. - */ - subresourceIntegrity?: boolean; - /** - * The full path for the TypeScript configuration file, relative to the current workspace. - */ - tsConfig: string; - /** - * Use a separate bundle containing only vendor libraries. - */ - vendorChunk?: boolean; - /** - * Resolve vendor packages sourcemaps. - * @deprecated - */ - vendorSourceMap?: boolean; - /** - * Adds more details to output logging. - */ - verbose?: boolean; - /** - * Run build when files change. - */ - watch?: boolean; - /** - * TypeScript configuration for Web Worker modules. - */ - webWorkerTsConfig?: string; -} - -export type AssetPattern = AssetPatternClass | string; - -export interface AssetPatternClass { - /** - * The pattern to match. - */ - glob: string; - /** - * An array of globs to ignore. - */ - ignore?: string[]; - /** - * The input directory path in which to apply 'glob'. Defaults to the project root. - */ - input: string; - /** - * Absolute path within the output. - */ - output: string; -} - -export interface Budget { - /** - * The baseline size for comparison. - */ - baseline?: string; - /** - * The threshold for error relative to the baseline (min & max). - */ - error?: string; - /** - * The maximum threshold for error relative to the baseline. - */ - maximumError?: string; - /** - * The maximum threshold for warning relative to the baseline. - */ - maximumWarning?: string; - /** - * The minimum threshold for error relative to the baseline. - */ - minimumError?: string; - /** - * The minimum threshold for warning relative to the baseline. - */ - minimumWarning?: string; - /** - * The name of the bundle. - */ - name?: string; - /** - * The type of budget. - */ - type: Type; - /** - * The threshold for warning relative to the baseline (min & max). - */ - warning?: string; -} - -/** - * The type of budget. - */ -export enum Type { - All = 'all', - AllScript = 'allScript', - Any = 'any', - AnyComponentStyle = 'anyComponentStyle', - AnyScript = 'anyScript', - Bundle = 'bundle', - Initial = 'initial', -} - -/** - * Define the crossorigin attribute setting of elements that provide CORS support. - */ -export enum CrossOrigin { - Anonymous = 'anonymous', - None = 'none', - UseCredentials = 'use-credentials', -} - -export interface FileReplacement { - replace?: string; - replaceWith?: string; - src?: string; - with?: string; -} - -/** - * How to handle missing translations for i18n. - */ -export enum I18NMissingTranslation { - Error = 'error', - Ignore = 'ignore', - Warning = 'warning', -} - -/** - * Configures the generation of the application's HTML index. - */ -export type IndexUnion = IndexObject | string; - -export interface IndexObject { - /** - * The path of a file to use for the application's generated HTML index. - */ - input: string; - /** - * The output path of the application's generated HTML index file. The full provided path - * will be used and will be considered relative to the application's configured output path. - */ - output?: string; -} - -export type Localize = string[] | boolean; - -/** - * Enables optimization of the build output. - */ -export type OptimizationUnion = boolean | OptimizationClass; - -export interface OptimizationClass { - /** - * Enables optimization of the scripts output. - */ - scripts?: boolean; - /** - * Enables optimization of the styles output. - */ - styles?: boolean; -} - -/** - * Define the output filename cache-busting hashing mode. - */ -export enum OutputHashing { - All = 'all', - Bundles = 'bundles', - Media = 'media', - None = 'none', -} - -export type ExtraEntryPoint = ExtraEntryPointClass | string; - -export interface ExtraEntryPointClass { - /** - * The bundle name for this extra entry point. - */ - bundleName?: string; - /** - * If the bundle will be referenced in the HTML file. - */ - inject?: boolean; - /** - * The file to include. - */ - input: string; - /** - * If the bundle will be lazy loaded. - */ - lazy?: boolean; -} - -/** - * Output sourcemaps. - */ -export type SourceMapUnion = boolean | SourceMapClass; - -export interface SourceMapClass { - /** - * Output sourcemaps used for error reporting tools. - */ - hidden?: boolean; - /** - * Output sourcemaps for all scripts. - */ - scripts?: boolean; - /** - * Output sourcemaps for all styles. - */ - styles?: boolean; - /** - * Resolve vendor packages sourcemaps. - */ - vendor?: boolean; -} - -/** - * Options to pass to style preprocessors. - */ -export interface StylePreprocessorOptions { - /** - * Paths to include. Paths will be resolved to project root. - */ - includePaths?: string[]; -} diff --git a/packages/web/src/utils/third-party/cli-files/models/build-options.ts b/packages/web/src/utils/third-party/cli-files/models/build-options.ts deleted file mode 100644 index 7cd3c6d67b..0000000000 --- a/packages/web/src/utils/third-party/cli-files/models/build-options.ts +++ /dev/null @@ -1,96 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// TODO: cleanup this file, it's copied as is from Angular CLI. - -import { ScriptTarget } from 'typescript'; -import { - AssetPatternClass, - Budget, - ExtraEntryPoint, - OptimizationClass, - SourceMapClass, -} from '../../browser/schema'; -import { NormalizedFileReplacement } from '../../utils/normalize-file-replacements'; - -export interface BuildOptions { - optimization: OptimizationClass; - environment?: string; - outputPath: string; - resourcesOutputPath?: string; - aot?: boolean; - sourceMap: SourceMapClass; - /** @deprecated use sourceMap instead */ - vendorSourceMap?: boolean; - /** @deprecated */ - evalSourceMap?: boolean; - vendorChunk?: boolean; - commonChunk?: boolean; - runtimeChunk?: boolean; - baseHref?: string; - deployUrl?: string; - verbose?: boolean; - progress?: boolean; - i18nFile?: string; - i18nFormat?: string; - i18nLocale?: string; - i18nMissingTranslation?: string; - extractCss?: boolean; - bundleDependencies?: 'none' | 'all'; - watch?: boolean; - outputHashing?: string; - poll?: number; - app?: string; - deleteOutputPath?: boolean; - preserveSymlinks?: boolean; - extractLicenses?: boolean; - buildOptimizer?: boolean; - namedChunks?: boolean; - subresourceIntegrity?: boolean; - serviceWorker?: boolean; - webWorkerTsConfig?: string; - skipAppShell?: boolean; - statsJson: boolean; - forkTypeChecker: boolean; - profile?: boolean; - es5BrowserSupport?: boolean; - - main: string; - polyfills?: string; - budgets: Budget[]; - assets: AssetPatternClass[]; - scripts: ExtraEntryPoint[]; - styles: ExtraEntryPoint[]; - stylePreprocessorOptions?: { includePaths: string[] }; - lazyModules: string[]; - platform?: 'browser' | 'server'; - fileReplacements: NormalizedFileReplacement[]; - /** @deprecated use only for compatibility in 8.x; will be removed in 9.0 */ - rebaseRootRelativeCssUrls?: boolean; - - /* Append script target version to filename. */ - esVersionInFileName?: boolean; - - /* When specified it will be used instead of the script target in the tsconfig.json. */ - scriptTargetOverride?: ScriptTarget; -} - -export interface WebpackTestOptions extends BuildOptions { - codeCoverage?: boolean; - codeCoverageExclude?: string[]; -} - -export interface WebpackConfigOptions { - root: string; - projectRoot: string; - sourceRoot?: string; - buildOptions: T; - tsConfig: any; - tsConfigPath: string; - supportES2015: boolean; -} diff --git a/packages/web/src/utils/third-party/cli-files/models/webpack-configs/utils.ts b/packages/web/src/utils/third-party/cli-files/models/webpack-configs/utils.ts deleted file mode 100644 index 594ea16e8f..0000000000 --- a/packages/web/src/utils/third-party/cli-files/models/webpack-configs/utils.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -// tslint:disable -// TODO: cleanup this file, it's copied as is from Angular CLI. - -import { basename } from 'path'; -import { normalizePath } from '@nrwl/devkit'; -import { ExtraEntryPoint, ExtraEntryPointClass } from '../../../browser/schema'; -import { ScriptTarget } from 'typescript'; - -export interface HashFormat { - chunk: string; - extract: string; - file: string; - script: string; -} - -export function getOutputHashFormat(option: string, length = 20): HashFormat { - const hashFormats: { [option: string]: HashFormat } = { - none: { chunk: '', extract: '', file: '', script: '' }, - media: { chunk: '', extract: '', file: `.[hash:${length}]`, script: '' }, - bundles: { - chunk: `.[chunkhash:${length}]`, - extract: `.[contenthash:${length}]`, - file: '', - script: `.[hash:${length}]`, - }, - all: { - chunk: `.[chunkhash:${length}]`, - extract: `.[contenthash:${length}]`, - file: `.[hash:${length}]`, - script: `.[hash:${length}]`, - }, - }; - return hashFormats[option] || hashFormats['none']; -} - -// todo: replace with Omit when we update to TS 3.5 -type Omit = Pick>; -export type NormalizedEntryPoint = Required>; - -export function normalizeExtraEntryPoints( - extraEntryPoints: ExtraEntryPoint[], - defaultBundleName: string -): NormalizedEntryPoint[] { - return extraEntryPoints.map((entry) => { - let normalizedEntry; - if (typeof entry === 'string') { - normalizedEntry = { - input: entry, - inject: true, - bundleName: defaultBundleName, - }; - } else { - const { lazy, inject = true, ...newEntry } = entry; - const injectNormalized = entry.lazy !== undefined ? !entry.lazy : inject; - let bundleName; - - if (entry.bundleName) { - bundleName = entry.bundleName; - } else if (!injectNormalized) { - // Lazy entry points use the file name as bundle name. - bundleName = basename( - normalizePath( - entry.input.replace(/\.(js|css|scss|sass|less|styl)$/i, '') - ) - ); - } else { - bundleName = defaultBundleName; - } - - normalizedEntry = { ...newEntry, inject: injectNormalized, bundleName }; - } - - return normalizedEntry; - }); -} - -/** - * Returns an ES version file suffix to differentiate between various builds. - */ -export function getEsVersionForFileName( - scriptTargetOverride: ScriptTarget | undefined, - esVersionInFileName = false -): string { - return scriptTargetOverride && esVersionInFileName - ? `-${ScriptTarget[scriptTargetOverride].toLowerCase()}` - : ''; -} diff --git a/packages/web/src/utils/third-party/cli-files/plugins/index-html-webpack-plugin.ts b/packages/web/src/utils/third-party/cli-files/plugins/index-html-webpack-plugin.ts deleted file mode 100644 index b918a008ee..0000000000 --- a/packages/web/src/utils/third-party/cli-files/plugins/index-html-webpack-plugin.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as webpack from 'webpack'; -import { basename, dirname, extname } from 'path'; -import { FileInfo } from '../utils/index-file/augment-index-html'; -import { - IndexHtmlGenerator, - IndexHtmlGeneratorOptions, - IndexHtmlGeneratorProcessOptions, -} from '../utils/index-file/index-html-generator'; - -export interface IndexHtmlWebpackPluginOptions - extends IndexHtmlGeneratorOptions, - Omit< - IndexHtmlGeneratorProcessOptions, - 'files' | 'noModuleFiles' | 'moduleFiles' - > { - noModuleEntrypoints: string[]; - moduleEntrypoints: string[]; -} - -type Compiler = any; - -const PLUGIN_NAME = 'index-html-webpack-plugin'; - -export class IndexHtmlWebpackPlugin extends IndexHtmlGenerator { - private _compilation: any | undefined; - - get compilation(): any { - if (this._compilation) { - return this._compilation; - } - - throw new Error('compilation is undefined.'); - } - - constructor(readonly options: IndexHtmlWebpackPluginOptions) { - super(options); - } - - apply(compiler: Compiler) { - compiler.hooks.thisCompilation.tap(PLUGIN_NAME, (compilation) => { - this._compilation = compilation; - compilation.hooks.processAssets.tapPromise( - { - name: PLUGIN_NAME, - stage: webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE + 1, - }, - callback - ); - }); - - function addWarning(compilation: any, message: string): void { - compilation.warnings.push(new this.webpack.WebpackError(message)); - } - - function addError(compilation: any, message: string): void { - compilation.errors.push(new this.webpack.WebpackError(message)); - } - - const callback = async (assets: Record) => { - // Get all files for selected entrypoints - const files: FileInfo[] = []; - const noModuleFiles: FileInfo[] = []; - const moduleFiles: FileInfo[] = []; - - try { - for (const [entryName, entrypoint] of this.compilation.entrypoints) { - const entryFiles: FileInfo[] = entrypoint - ?.getFiles() - ?.filter((f) => !f.endsWith('.hot-update.js')) - ?.map( - (f: string): FileInfo => ({ - name: entryName, - file: f, - extension: extname(f), - }) - ); - - if (!entryFiles) { - continue; - } - - if (this.options.noModuleEntrypoints.includes(entryName)) { - noModuleFiles.push(...entryFiles); - } else if (this.options.moduleEntrypoints.includes(entryName)) { - moduleFiles.push(...entryFiles); - } else { - files.push(...entryFiles); - } - } - - const { content, warnings, errors } = await this.process({ - files, - noModuleFiles, - moduleFiles, - outputPath: dirname(this.options.outputPath), - baseHref: this.options.baseHref, - lang: this.options.lang, - }); - - assets[this.options.outputPath] = new webpack.sources.RawSource( - content - ); - - warnings.forEach((msg) => addWarning(this.compilation, msg)); - errors.forEach((msg) => addError(this.compilation, msg)); - } catch (error) { - addError(this.compilation, error.message); - } - }; - } - - async readAsset(path: string): Promise { - const data = this.compilation.assets[basename(path)].source(); - - return typeof data === 'string' ? data : data.toString(); - } - - protected async readIndex(path: string): Promise { - return new Promise((resolve, reject) => { - this.compilation.inputFileSystem.readFile( - path, - (err?: Error, data?: string | Buffer) => { - if (err) { - reject(err); - - return; - } - - this.compilation.fileDependencies.add(path); - resolve(data?.toString() ?? ''); - } - ); - }); - } -} diff --git a/packages/web/src/utils/third-party/cli-files/plugins/named-chunks-plugin.ts b/packages/web/src/utils/third-party/cli-files/plugins/named-chunks-plugin.ts deleted file mode 100644 index d20af00f76..0000000000 --- a/packages/web/src/utils/third-party/cli-files/plugins/named-chunks-plugin.ts +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { Compiler } from 'webpack'; - -export class NamedLazyChunksPlugin { - constructor() {} - apply(compiler: Compiler): void { - // Webpack doesn't export these so the deep imports can potentially break. - // There doesn't seem to exist any ergonomic way to alter chunk names for non-context lazy chunks - // (https://github.com/webpack/webpack/issues/9075) so this is the best alternative for now. - const ImportDependency = require('webpack/lib/dependencies/ImportDependency'); - const ImportDependenciesBlock = require('webpack/lib/dependencies/ImportDependenciesBlock'); - const Template = require('webpack/lib/Template'); - compiler.hooks.compilation.tap( - 'named-lazy-chunks-plugin', - (compilation) => { - // The dependencyReference hook isn't in the webpack typings so we have to type it as any. - // tslint:disable-next-line: no-any - (compilation.hooks as any).dependencyReference.tap( - 'named-lazy-chunks-plugin', - // tslint:disable-next-line: no-any - (_: any, dependency: any) => { - if ( - // Check this dependency is from an `import()` statement. - dependency instanceof ImportDependency && - dependency.block instanceof ImportDependenciesBlock && - // Don't rename chunks that already have a name. - dependency.block.chunkName === null - ) { - // Convert the request to a valid chunk name using the same logic used - // in webpack/lib/ContextModule.js - dependency.block.chunkName = Template.toPath(dependency.request); - } - } - ); - } - ); - } -} diff --git a/packages/web/src/utils/third-party/cli-files/plugins/raw-css-loader.ts b/packages/web/src/utils/third-party/cli-files/plugins/raw-css-loader.ts deleted file mode 100644 index 851bff7069..0000000000 --- a/packages/web/src/utils/third-party/cli-files/plugins/raw-css-loader.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export default function (content: string, map: object) { - const stringifiedContent = JSON.stringify(content); - const stringifiedMap = map ? JSON.stringify(map) : `''`; - - return `module.exports = [[module.id, ${stringifiedContent}, '', ${stringifiedMap}]]`; -} diff --git a/packages/web/src/utils/third-party/cli-files/plugins/webpack.ts b/packages/web/src/utils/third-party/cli-files/plugins/webpack.ts deleted file mode 100644 index f38b9a57e6..0000000000 --- a/packages/web/src/utils/third-party/cli-files/plugins/webpack.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Exports the webpack plugins we use internally. -export { - ScriptsWebpackPlugin, - ScriptsWebpackPluginOptions, -} from './scripts-webpack-plugin'; -export { - RemoveHashPlugin, - RemoveHashPluginOptions, -} from './remove-hash-plugin'; -export { - default as PostcssCliResources, - PostcssCliResourcesOptions, -} from './postcss-cli-resources'; - -import { join } from 'path'; -export const RawCssLoader = require.resolve(join(__dirname, 'raw-css-loader')); diff --git a/packages/web/src/utils/third-party/cli-files/utilities/index-file/__snapshots__/augment-index-html.spec.ts.snap b/packages/web/src/utils/third-party/cli-files/utilities/index-file/__snapshots__/augment-index-html.spec.ts.snap deleted file mode 100644 index df3f4e3a60..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utilities/index-file/__snapshots__/augment-index-html.spec.ts.snap +++ /dev/null @@ -1,7 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`augment-index-html can generate index.html 1`] = `""`; - -exports[`augment-index-html should emit correct script tags when having 'module' and 'non-module' js 1`] = `""`; - -exports[`augment-index-html should not add 'module' and 'non-module' attr to js files which are in both module formats 1`] = `""`; diff --git a/packages/web/src/utils/third-party/cli-files/utilities/index-file/augment-index-html.spec.ts b/packages/web/src/utils/third-party/cli-files/utilities/index-file/augment-index-html.spec.ts deleted file mode 100644 index 9c53a68985..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utilities/index-file/augment-index-html.spec.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { - AugmentIndexHtmlOptions, - FileInfo, - augmentIndexHtml, -} from './augment-index-html'; - -describe('augment-index-html', () => { - const indexGeneratorOptions: AugmentIndexHtmlOptions = { - input: 'index.html', - inputContent: '', - baseHref: '/', - sri: false, - files: [], - loadOutputFile: (_fileName: string) => '', - entrypoints: ['scripts', 'polyfills', 'main', 'styles'], - }; - - it('can generate index.html', async () => { - const source = augmentIndexHtml({ - ...indexGeneratorOptions, - files: [ - { file: 'styles.css', extension: '.css', name: 'styles' }, - { file: 'runtime.js', extension: '.js', name: 'main' }, - { file: 'main.js', extension: '.js', name: 'main' }, - { file: 'runtime.js', extension: '.js', name: 'polyfills' }, - { file: 'polyfills.js', extension: '.js', name: 'polyfills' }, - ], - }); - - const html = await source; - expect(html).toMatchSnapshot(); - }); - - it(`should emit correct script tags when having 'module' and 'non-module' js`, async () => { - const es2015JsFiles: FileInfo[] = [ - { file: 'runtime-es2015.js', extension: '.js', name: 'main' }, - { file: 'main-es2015.js', extension: '.js', name: 'main' }, - { file: 'runtime-es2015.js', extension: '.js', name: 'polyfills' }, - { file: 'polyfills-es2015.js', extension: '.js', name: 'polyfills' }, - ]; - - const es5JsFiles: FileInfo[] = [ - { file: 'runtime-es5.js', extension: '.js', name: 'main' }, - { file: 'main-es5.js', extension: '.js', name: 'main' }, - { file: 'runtime-es5.js', extension: '.js', name: 'polyfills' }, - { file: 'polyfills-es5.js', extension: '.js', name: 'polyfills' }, - ]; - - const source = augmentIndexHtml({ - ...indexGeneratorOptions, - files: [ - { file: 'styles.css', extension: '.css', name: 'styles' }, - { file: 'styles.css', extension: '.css', name: 'styles' }, - ], - moduleFiles: es2015JsFiles, - noModuleFiles: es5JsFiles, - }); - - const html = await source; - expect(html).toMatchSnapshot(); - }); - - it(`should not add 'module' and 'non-module' attr to js files which are in both module formats`, async () => { - const es2015JsFiles: FileInfo[] = [ - { file: 'scripts.js', extension: '.js', name: 'scripts' }, - { file: 'main-es2015.js', extension: '.js', name: 'main' }, - ]; - - const es5JsFiles: FileInfo[] = [ - { file: 'scripts.js', extension: '.js', name: 'scripts' }, - { file: 'main-es5.js', extension: '.js', name: 'main' }, - ]; - - const source = augmentIndexHtml({ - ...indexGeneratorOptions, - files: [ - { file: 'styles.css', extension: '.css', name: 'styles' }, - { file: 'styles.css', extension: '.css', name: 'styles' }, - ], - moduleFiles: es2015JsFiles, - noModuleFiles: es5JsFiles, - }); - - const html = await source; - expect(html).toMatchSnapshot(); - }); -}); diff --git a/packages/web/src/utils/third-party/cli-files/utilities/index-file/write-index-html.ts b/packages/web/src/utils/third-party/cli-files/utilities/index-file/write-index-html.ts deleted file mode 100644 index 207077f7ab..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utilities/index-file/write-index-html.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { dirname, join } from 'path'; -import { ExtraEntryPoint } from '../../../browser/schema'; -import { generateEntryPoints } from '../package-chunk-sort'; -import { stripBom } from '../strip-bom'; -import { - augmentIndexHtml, - CrossOriginValue, - FileInfo, -} from './augment-index-html'; -import { readFileSync, writeFileSync } from 'fs'; -import { interpolateEnvironmentVariablesToIndex } from '../../../../interpolate-env-variables-to-index'; -import { EmittedFile } from '../../../../run-webpack'; - -type ExtensionFilter = '.js' | '.css'; - -export interface WriteIndexHtmlOptions { - outputPath: string; - indexPath: string; - files?: EmittedFile[]; - noModuleFiles?: EmittedFile[]; - moduleFiles?: EmittedFile[]; - baseHref?: string; - deployUrl?: string; - sri?: boolean; - scripts?: ExtraEntryPoint[]; - styles?: ExtraEntryPoint[]; - postTransform?: IndexHtmlTransform; - crossOrigin?: CrossOriginValue; -} - -export type IndexHtmlTransform = (content: string) => Promise; - -export async function writeIndexHtml({ - outputPath, - indexPath, - files = [], - noModuleFiles = [], - moduleFiles = [], - baseHref, - deployUrl, - sri = false, - scripts = [], - styles = [], - postTransform, - crossOrigin, -}: WriteIndexHtmlOptions) { - let content = readFileSync(indexPath).toString(); - content = stripBom(content); - content = augmentIndexHtml({ - input: outputPath, - inputContent: interpolateEnvironmentVariablesToIndex(content, deployUrl), - baseHref, - deployUrl, - crossOrigin, - sri, - entrypoints: generateEntryPoints({ scripts, styles }), - files: filterAndMapBuildFiles(files, ['.js', '.css']), - noModuleFiles: filterAndMapBuildFiles(noModuleFiles, '.js'), - moduleFiles: filterAndMapBuildFiles(moduleFiles, '.js'), - loadOutputFile: (filePath) => - readFileSync(join(dirname(outputPath), filePath)).toString(), - }); - if (postTransform) { - content = await postTransform(content); - } - - writeFileSync(outputPath, content); -} - -function filterAndMapBuildFiles( - files: EmittedFile[], - extensionFilter: ExtensionFilter | ExtensionFilter[] -): FileInfo[] { - const filteredFiles: FileInfo[] = []; - const validExtensions: string[] = Array.isArray(extensionFilter) - ? extensionFilter - : [extensionFilter]; - - for (const { file, name, extension, initial } of files) { - if (name && initial && validExtensions.includes(extension)) { - filteredFiles.push({ file, extension, name }); - } - } - - return filteredFiles; -} diff --git a/packages/web/src/utils/third-party/cli-files/utilities/is-directory.ts b/packages/web/src/utils/third-party/cli-files/utilities/is-directory.ts deleted file mode 100644 index 230135cebf..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utilities/is-directory.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -// tslint:disable -// TODO: cleanup this file, it's copied as is from Angular CLI. - -import { statSync } from 'fs'; - -export function isDirectory(path: string) { - try { - return statSync(path).isDirectory(); - } catch (_) { - return false; - } -} diff --git a/packages/web/src/utils/third-party/cli-files/utilities/strip-bom.ts b/packages/web/src/utils/third-party/cli-files/utilities/strip-bom.ts deleted file mode 100644 index f4aba38228..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utilities/strip-bom.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -// tslint:disable -// TODO: cleanup this file, it's copied as is from Angular CLI. - -// Strip BOM from file data. -// https://stackoverflow.com/questions/24356713 -export function stripBom(data: string) { - return data.replace(/^\uFEFF/, ''); -} diff --git a/packages/web/src/utils/third-party/cli-files/utils/index-file/augment-index-html.ts b/packages/web/src/utils/third-party/cli-files/utils/index-file/augment-index-html.ts deleted file mode 100644 index 7031cd5337..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utils/index-file/augment-index-html.ts +++ /dev/null @@ -1,239 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { createHash } from 'crypto'; -import { htmlRewritingStream } from './html-rewriting-stream'; - -export type LoadOutputFileFunctionType = (file: string) => Promise; - -export type CrossOriginValue = 'none' | 'anonymous' | 'use-credentials'; - -export interface AugmentIndexHtmlOptions { - /* Input contents */ - html: string; - baseHref?: string; - deployUrl?: string; - sri: boolean; - /** crossorigin attribute setting of elements that provide CORS support */ - crossOrigin?: CrossOriginValue; - /* - * Files emitted by the build. - * Js files will be added without 'nomodule' nor 'module'. - */ - files: FileInfo[]; - /** Files that should be added using 'nomodule'. */ - noModuleFiles?: FileInfo[]; - /** Files that should be added using 'module'. */ - moduleFiles?: FileInfo[]; - /* - * Function that loads a file used. - * This allows us to use different routines within the IndexHtmlWebpackPlugin and - * when used without this plugin. - */ - loadOutputFile: LoadOutputFileFunctionType; - /** Used to sort the inseration of files in the HTML file */ - entrypoints: string[]; - /** Used to set the document default locale */ - lang?: string; -} - -export interface FileInfo { - file: string; - name: string; - extension: string; -} - -/* - * Helper function used by the IndexHtmlWebpackPlugin. - * Can also be directly used by builder, e. g. in order to generate an index.html - * after processing several configurations in order to build different sets of - * bundles for differential serving. - */ -export async function augmentIndexHtml( - params: AugmentIndexHtmlOptions -): Promise { - const { - loadOutputFile, - files, - noModuleFiles = [], - moduleFiles = [], - entrypoints, - sri, - deployUrl = '', - lang, - baseHref, - html, - } = params; - - let { crossOrigin = 'none' } = params; - if (sri && crossOrigin === 'none') { - crossOrigin = 'anonymous'; - } - - const stylesheets = new Set(); - const scripts = new Set(); - - // Sort files in the order we want to insert them by entrypoint and dedupes duplicates - const mergedFiles = [...moduleFiles, ...noModuleFiles, ...files]; - for (const entrypoint of entrypoints) { - for (const { extension, file, name } of mergedFiles) { - if (name !== entrypoint) { - continue; - } - - switch (extension) { - case '.js': - scripts.add(file); - break; - case '.css': - stylesheets.add(file); - break; - } - } - } - - let scriptTags: string[] = []; - for (const script of scripts) { - const attrs = [`src="${deployUrl}${script}"`]; - - if (crossOrigin !== 'none') { - attrs.push(`crossorigin="${crossOrigin}"`); - } - - // We want to include nomodule or module when a file is not common amongs all - // such as runtime.js - const scriptPredictor = ({ file }: FileInfo): boolean => file === script; - if (!files.some(scriptPredictor)) { - // in some cases for differential loading file with the same name is available in both - // nomodule and module such as scripts.js - // we shall not add these attributes if that's the case - const isNoModuleType = noModuleFiles.some(scriptPredictor); - const isModuleType = moduleFiles.some(scriptPredictor); - - if (isNoModuleType && !isModuleType) { - attrs.push('nomodule', 'defer'); - } else if (isModuleType && !isNoModuleType) { - attrs.push('type="module"'); - } else { - attrs.push('defer'); - } - } else { - attrs.push('defer'); - } - - if (sri) { - const content = await loadOutputFile(script); - attrs.push(generateSriAttributes(content)); - } - - scriptTags.push(``); - } - - let linkTags: string[] = []; - for (const stylesheet of stylesheets) { - const attrs = [`rel="stylesheet"`, `href="${deployUrl}${stylesheet}"`]; - - if (crossOrigin !== 'none') { - attrs.push(`crossorigin="${crossOrigin}"`); - } - - if (sri) { - const content = await loadOutputFile(stylesheet); - attrs.push(generateSriAttributes(content)); - } - - linkTags.push(``); - } - - const { rewriter, transformedContent } = await htmlRewritingStream(html); - const baseTagExists = html.includes(' { - switch (tag.tagName) { - case 'html': - // Adjust document locale if specified - if (isString(lang)) { - updateAttribute(tag, 'lang', lang); - } - break; - case 'head': - // Base href should be added before any link, meta tags - if (!baseTagExists && isString(baseHref)) { - rewriter.emitStartTag(tag); - rewriter.emitRaw(``); - - return; - } - break; - case 'base': - // Adjust base href if specified - if (isString(baseHref)) { - updateAttribute(tag, 'href', baseHref); - } - break; - } - - rewriter.emitStartTag(tag); - }) - .on('endTag', (tag) => { - switch (tag.tagName) { - case 'head': - for (const linkTag of linkTags) { - rewriter.emitRaw(linkTag); - } - - linkTags = []; - break; - case 'body': - // Add script tags - for (const scriptTag of scriptTags) { - rewriter.emitRaw(scriptTag); - } - - scriptTags = []; - break; - } - - rewriter.emitEndTag(tag); - }); - - const content = await transformedContent; - - if (linkTags.length || scriptTags.length) { - // In case no body/head tags are not present (dotnet partial templates) - return linkTags.join('') + scriptTags.join('') + content; - } - - return content; -} - -function generateSriAttributes(content: string): string { - const algo = 'sha384'; - const hash = createHash(algo).update(content, 'utf8').digest('base64'); - - return `integrity="${algo}-${hash}"`; -} - -function updateAttribute( - tag: { attrs: { name: string; value: string }[] }, - name: string, - value: string -): void { - const index = tag.attrs.findIndex((a) => a.name === name); - const newValue = { name, value }; - - if (index === -1) { - tag.attrs.push(newValue); - } else { - tag.attrs[index] = newValue; - } -} - -function isString(value: unknown): value is string { - return typeof value === 'string'; -} diff --git a/packages/web/src/utils/third-party/cli-files/utils/index-file/html-rewriting-stream.ts b/packages/web/src/utils/third-party/cli-files/utils/index-file/html-rewriting-stream.ts deleted file mode 100644 index e2b2bc079d..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utils/index-file/html-rewriting-stream.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { Readable, Writable } from 'stream'; - -export async function htmlRewritingStream(content: string): Promise<{ - rewriter: import('parse5-html-rewriting-stream'); - transformedContent: Promise; -}> { - const chunks: Buffer[] = []; - const rewriter = new (await import('parse5-html-rewriting-stream'))(); - - return { - rewriter, - transformedContent: new Promise((resolve) => { - new Readable({ - encoding: 'utf8', - read(): void { - this.push(Buffer.from(content)); - this.push(null); - }, - }) - .pipe(rewriter) - .pipe( - new Writable({ - write( - chunk: string | Buffer, - encoding: string | undefined, - callback: Function - ): void { - chunks.push( - typeof chunk === 'string' - ? Buffer.from(chunk, encoding as BufferEncoding) - : chunk - ); - callback(); - }, - final(callback: (error?: Error) => void): void { - callback(); - resolve(Buffer.concat(chunks).toString()); - }, - }) - ); - }), - }; -} diff --git a/packages/web/src/utils/third-party/cli-files/utils/index-file/index-html-generator.ts b/packages/web/src/utils/third-party/cli-files/utils/index-file/index-html-generator.ts deleted file mode 100644 index 07d13411db..0000000000 --- a/packages/web/src/utils/third-party/cli-files/utils/index-file/index-html-generator.ts +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as fs from 'fs'; -import { join } from 'path'; -import { - CrossOriginValue, - FileInfo, - augmentIndexHtml, -} from './augment-index-html'; - -function stripBom(data: string) { - return data.replace(/^\uFEFF/, ''); -} - -type IndexHtmlGeneratorPlugin = ( - html: string, - options: IndexHtmlGeneratorProcessOptions -) => Promise; - -export interface IndexHtmlGeneratorProcessOptions { - lang?: string | undefined; - baseHref?: string | undefined; - outputPath: string; - files: FileInfo[]; - noModuleFiles: FileInfo[]; - moduleFiles: FileInfo[]; -} - -export interface IndexHtmlGeneratorOptions { - indexPath: string; - deployUrl?: string; - sri?: boolean; - entrypoints: string[]; - postTransform?: IndexHtmlTransform; - crossOrigin?: CrossOriginValue; - optimization?: any; - WOFFSupportNeeded?: boolean; -} - -export type IndexHtmlTransform = (content: string) => Promise; - -export interface IndexHtmlTransformResult { - content: string; - warnings: string[]; - errors: string[]; -} - -export class IndexHtmlGenerator { - private readonly plugins: IndexHtmlGeneratorPlugin[]; - - constructor(readonly options: IndexHtmlGeneratorOptions) { - const extraPlugins: IndexHtmlGeneratorPlugin[] = []; - this.plugins = [ - augmentIndexHtmlPlugin(this), - ...extraPlugins, - postTransformPlugin(this), - ]; - } - - async process( - options: IndexHtmlGeneratorProcessOptions - ): Promise { - let content = stripBom(await this.readIndex(this.options.indexPath)); - const warnings: string[] = []; - const errors: string[] = []; - - for (const plugin of this.plugins) { - const result = await plugin(content, options); - if (typeof result === 'string') { - content = result; - } else { - content = result.content; - - if (result.warnings.length) { - warnings.push(...result.warnings); - } - - if (result.errors.length) { - errors.push(...result.errors); - } - } - } - - return { - content, - warnings, - errors, - }; - } - - async readAsset(path: string): Promise { - return fs.promises.readFile(path, 'utf-8'); - } - - protected async readIndex(path: string): Promise { - return fs.promises.readFile(path, 'utf-8'); - } -} - -function augmentIndexHtmlPlugin( - generator: IndexHtmlGenerator -): IndexHtmlGeneratorPlugin { - const { - deployUrl, - crossOrigin, - sri = false, - entrypoints, - } = generator.options; - - return async (html, options) => { - const { - lang, - baseHref, - outputPath = '', - noModuleFiles, - files, - moduleFiles, - } = options; - - return augmentIndexHtml({ - html, - baseHref, - deployUrl, - crossOrigin, - sri, - lang, - entrypoints, - loadOutputFile: (filePath) => - generator.readAsset(join(outputPath, filePath)), - noModuleFiles, - moduleFiles, - files, - }); - }; -} - -function postTransformPlugin({ - options, -}: IndexHtmlGenerator): IndexHtmlGeneratorPlugin { - return async (html) => - options.postTransform ? options.postTransform(html) : html; -} diff --git a/packages/web/src/utils/third-party/utils/default-progress.ts b/packages/web/src/utils/third-party/utils/default-progress.ts deleted file mode 100644 index 258412b460..0000000000 --- a/packages/web/src/utils/third-party/utils/default-progress.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export function defaultProgress(progress: boolean | undefined): boolean { - if (progress === undefined) { - return process.stdout.isTTY === true; - } - - return progress; -} diff --git a/packages/web/src/utils/third-party/utils/delete-output-dir.ts b/packages/web/src/utils/third-party/utils/delete-output-dir.ts deleted file mode 100644 index 892340a474..0000000000 --- a/packages/web/src/utils/third-party/utils/delete-output-dir.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { resolve } from 'path'; -import { existsSync, unlinkSync } from 'fs'; - -/** - * Delete an output directory, but error out if it's the root of the project. - */ -export function deleteOutputDir(root: string, outputPath: string) { - const resolvedOutputPath = resolve(root, outputPath); - if (resolvedOutputPath === root) { - throw new Error('Output path MUST not be project root directory!'); - } - - const exists = existsSync(resolvedOutputPath); - if (exists) { - unlinkSync(resolvedOutputPath); - } -} diff --git a/packages/web/src/utils/third-party/utils/index.ts b/packages/web/src/utils/third-party/utils/index.ts deleted file mode 100644 index c529716e91..0000000000 --- a/packages/web/src/utils/third-party/utils/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export * from './build-browser-features'; -export * from './default-progress'; -export * from './delete-output-dir'; -export * from './normalize-file-replacements'; -export * from './normalize-asset-patterns'; -export * from './normalize-source-maps'; -export * from './normalize-optimization'; -export * from './normalize-builder-schema'; diff --git a/packages/web/src/utils/third-party/utils/mangle-options.ts b/packages/web/src/utils/third-party/utils/mangle-options.ts deleted file mode 100644 index 60085e43c8..0000000000 --- a/packages/web/src/utils/third-party/utils/mangle-options.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -const mangleVariable = process.env['NG_BUILD_MANGLE']; -export const manglingDisabled = - !!mangleVariable && - (mangleVariable === '0' || mangleVariable.toLowerCase() === 'false'); diff --git a/packages/web/src/utils/third-party/utils/normalize-asset-patterns.ts b/packages/web/src/utils/third-party/utils/normalize-asset-patterns.ts deleted file mode 100644 index 6396162e5d..0000000000 --- a/packages/web/src/utils/third-party/utils/normalize-asset-patterns.ts +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { normalizePath } from '@nrwl/devkit'; -import { basename, dirname, relative, join, resolve } from 'path'; -import { AssetPattern, AssetPatternClass } from '../browser/schema'; -import { statSync } from 'fs'; - -export class MissingAssetSourceRootException extends Error { - constructor(path: String) { - super(`The ${path} asset path must start with the project source root.`); - } -} - -export function normalizeAssetPatterns( - assetPatterns: AssetPattern[], - root: string, - projectRoot: string, - maybeSourceRoot: string | undefined -): AssetPatternClass[] { - // When sourceRoot is not available, we default to ${projectRoot}/src. - const sourceRoot = maybeSourceRoot || join(projectRoot, 'src'); - const resolvedSourceRoot = resolve(root, sourceRoot); - - if (assetPatterns.length === 0) { - return []; - } - - return assetPatterns.map((assetPattern) => { - // Normalize string asset patterns to objects. - if (typeof assetPattern === 'string') { - const assetPath = normalizePath(assetPattern); - const resolvedAssetPath = resolve(root, assetPath); - - // Check if the string asset is within sourceRoot. - if (!resolvedAssetPath.startsWith(resolvedSourceRoot)) { - throw new MissingAssetSourceRootException(assetPattern); - } - - let glob: string, input: string, output: string; - let isDirectory = false; - - try { - isDirectory = statSync(resolvedAssetPath).isDirectory(); - } catch {} - - if (isDirectory) { - // Folders get a recursive star glob. - glob = '**/*'; - // Input directory is their original path. - input = assetPath; - } else { - // Files are their own glob. - glob = basename(assetPath); - // Input directory is their original dirname. - input = dirname(assetPath); - } - - // Output directory for both is the relative path from source root to input. - output = relative(resolvedSourceRoot, resolve(root, input)); - - // Return the asset pattern in object format. - return { glob, input, output }; - } else { - // It's already an AssetPatternObject, no need to convert. - return assetPattern; - } - }); -} diff --git a/packages/web/src/utils/third-party/utils/normalize-builder-schema.ts b/packages/web/src/utils/third-party/utils/normalize-builder-schema.ts deleted file mode 100644 index d90b0b184d..0000000000 --- a/packages/web/src/utils/third-party/utils/normalize-builder-schema.ts +++ /dev/null @@ -1,75 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { BuildOptions } from '../cli-files/models/build-options'; -import { - AssetPatternClass, - OptimizationClass, - Schema as BrowserBuilderSchema, - SourceMapClass, -} from '../browser/schema'; -import { normalizeAssetPatterns } from './normalize-asset-patterns'; -import { - NormalizedFileReplacement, - normalizeFileReplacements, -} from './normalize-file-replacements'; -import { normalizeOptimization } from './normalize-optimization'; -import { normalizeSourceMaps } from './normalize-source-maps'; - -/** - * A normalized browser builder schema. - */ -export type NormalizedBrowserBuilderSchema = BrowserBuilderSchema & - BuildOptions & { - sourceMap: SourceMapClass; - assets: AssetPatternClass[]; - fileReplacements: NormalizedFileReplacement[]; - optimization: OptimizationClass; - }; - -export function normalizeBrowserSchema( - root: string, - projectRoot: string, - sourceRoot: string | undefined, - options: BrowserBuilderSchema -): NormalizedBrowserBuilderSchema { - const normalizedSourceMapOptions = normalizeSourceMaps( - options.sourceMap || false - ); - normalizedSourceMapOptions.vendor = - normalizedSourceMapOptions.vendor || options.vendorSourceMap; - - return { - ...options, - assets: normalizeAssetPatterns( - options.assets || [], - root, - projectRoot, - sourceRoot - ), - fileReplacements: normalizeFileReplacements( - options.fileReplacements || [], - root - ), - optimization: normalizeOptimization(options.optimization), - sourceMap: normalizedSourceMapOptions, - - statsJson: options.statsJson || false, - forkTypeChecker: options.forkTypeChecker || false, - budgets: options.budgets || [], - scripts: options.scripts || [], - styles: options.styles || [], - stylePreprocessorOptions: { - includePaths: - (options.stylePreprocessorOptions && - options.stylePreprocessorOptions.includePaths) || - [], - }, - lazyModules: options.lazyModules || [], - }; -} diff --git a/packages/web/src/utils/third-party/utils/normalize-file-replacements.ts b/packages/web/src/utils/third-party/utils/normalize-file-replacements.ts deleted file mode 100644 index 8f651968a8..0000000000 --- a/packages/web/src/utils/third-party/utils/normalize-file-replacements.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { normalizePath } from '@nrwl/devkit'; -import { join } from 'path'; -import { existsSync } from 'fs'; -import { FileReplacement } from '../browser/schema'; - -export class MissingFileReplacementException extends Error { - constructor(path: String) { - super(`The ${path} path in file replacements does not exist.`); - } -} - -export interface NormalizedFileReplacement { - replace: string; - with: string; -} - -export function normalizeFileReplacements( - fileReplacements: FileReplacement[], - root: string -): NormalizedFileReplacement[] { - if (fileReplacements.length === 0) { - return []; - } - - const normalizedReplacement = fileReplacements.map((replacement) => - normalizeFileReplacement(replacement, root) - ); - - for (const { replace, with: replacementWith } of normalizedReplacement) { - if (!existsSync(replacementWith)) { - throw new MissingFileReplacementException(replacementWith); - } - - if (!existsSync(replace)) { - throw new MissingFileReplacementException(replace); - } - } - - return normalizedReplacement; -} - -function normalizeFileReplacement( - fileReplacement: FileReplacement, - root?: string -): NormalizedFileReplacement { - let replacePath: string; - let withPath: string; - if (fileReplacement.src && fileReplacement.replaceWith) { - replacePath = normalizePath(fileReplacement.src); - withPath = normalizePath(fileReplacement.replaceWith); - } else if (fileReplacement.replace && fileReplacement.with) { - replacePath = normalizePath(fileReplacement.replace); - withPath = normalizePath(fileReplacement.with); - } else { - throw new Error( - `Invalid file replacement: ${JSON.stringify(fileReplacement)}` - ); - } - - // TODO: For 7.x should this only happen if not absolute? - if (root) { - replacePath = join(root, replacePath); - } - if (root) { - withPath = join(root, withPath); - } - - return { replace: replacePath, with: withPath }; -} diff --git a/packages/web/src/utils/third-party/utils/normalize-optimization.ts b/packages/web/src/utils/third-party/utils/normalize-optimization.ts deleted file mode 100644 index 743181e522..0000000000 --- a/packages/web/src/utils/third-party/utils/normalize-optimization.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { OptimizationClass, OptimizationUnion } from '../browser/schema'; - -export function normalizeOptimization( - optimization: OptimizationUnion = false -): Required { - return { - scripts: - typeof optimization === 'object' ? !!optimization.scripts : optimization, - styles: - typeof optimization === 'object' ? !!optimization.styles : optimization, - }; -} diff --git a/packages/web/src/utils/third-party/utils/normalize-source-maps.ts b/packages/web/src/utils/third-party/utils/normalize-source-maps.ts deleted file mode 100644 index fcd0bb342e..0000000000 --- a/packages/web/src/utils/third-party/utils/normalize-source-maps.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @license - * Copyright Google Inc. All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { SourceMapClass, SourceMapUnion } from '../browser/schema'; - -export function normalizeSourceMaps(sourceMap: SourceMapUnion): SourceMapClass { - const scripts = typeof sourceMap === 'object' ? sourceMap.scripts : sourceMap; - const styles = typeof sourceMap === 'object' ? sourceMap.styles : sourceMap; - const hidden = (typeof sourceMap === 'object' && sourceMap.hidden) || false; - const vendor = (typeof sourceMap === 'object' && sourceMap.vendor) || false; - - return { - vendor, - hidden, - scripts, - styles, - }; -} diff --git a/packages/web/src/utils/types.ts b/packages/web/src/utils/types.ts deleted file mode 100644 index e943f8aab8..0000000000 --- a/packages/web/src/utils/types.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { FileReplacement } from './normalize'; - -export interface OptimizationOptions { - scripts: boolean; - styles: boolean; -} - -export interface BuildBuilderOptions { - main: string; - outputPath: string; - tsConfig: string; - watch?: boolean; - sourceMap?: boolean | 'hidden'; - optimization?: boolean | OptimizationOptions; - memoryLimit?: number; - maxWorkers?: number; - poll?: number; - - fileReplacements?: FileReplacement[]; - assets?: any[]; - - progress?: boolean; - statsJson?: boolean; - extractLicenses?: boolean; - verbose?: boolean; - - outputHashing?: any; - webpackConfig?: string; - - root?: string; - sourceRoot?: string; -} - -export interface AssetGlobPattern { - glob: string; - input: string; - output: string; - ignore?: string[]; -} diff --git a/packages/web/src/utils/web.config.ts b/packages/web/src/utils/web.config.ts index e2bb5d8a06..c291ce3b7f 100644 --- a/packages/web/src/utils/web.config.ts +++ b/packages/web/src/utils/web.config.ts @@ -1,20 +1,16 @@ import * as path from 'path'; -import { basename, posix, resolve } from 'path'; +import { posix, resolve } from 'path'; import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { ScriptTarget } from 'typescript'; import { getHashDigest, interpolateName } from 'loader-utils'; import { Configuration } from 'webpack'; -// TODO @FrozenPandaz we should remove the following imports -import { getBrowserConfig } from './third-party/cli-files/models/webpack-configs/browser'; -import { getCommonConfig } from './third-party/cli-files/models/webpack-configs/common'; -import { getStylesConfig } from './third-party/cli-files/models/webpack-configs/styles'; -import { IndexHtmlWebpackPlugin } from './third-party/cli-files/plugins/index-html-webpack-plugin'; -import { generateEntryPoints } from './third-party/cli-files/utilities/package-chunk-sort'; - -import { WebBuildBuilderOptions } from '../executors/build/build.impl'; +import { WebBuildExecutorOptions } from '../executors/build/build.impl'; import { convertBuildOptions } from './normalize'; import { getBaseWebpackPartial } from './config'; +import { getBrowserConfig } from './webpack/partials/browser'; +import { getCommonConfig } from './webpack/partials/common'; +import { getStylesConfig } from './webpack/partials/styles'; import MiniCssExtractPlugin = require('mini-css-extract-plugin'); import webpackMerge = require('webpack-merge'); import postcssImports = require('postcss-import'); @@ -31,7 +27,7 @@ export function getWebConfig( workspaceRoot, projectRoot, sourceRoot, - options: WebBuildBuilderOptions, + options: WebBuildExecutorOptions, esm?: boolean, isScriptOptimizeOn?: boolean, configuration?: string @@ -69,53 +65,18 @@ export function getWebConfig( esm, isScriptOptimizeOn ), - getStylesPartial( - wco.root, - wco.projectRoot, - wco.buildOptions, - options.extractCss - ), + getStylesPartial(wco.root, wco.projectRoot, wco.buildOptions, true), getCommonPartial(wco), - getBrowserPartial(wco, options, isScriptOptimizeOn), + getBrowserPartial(wco, options), ]); } -function getBrowserPartial( - wco: any, - options: WebBuildBuilderOptions, - isScriptOptimizeOn: boolean -) { - const config = getBrowserConfig(wco); - - if (!isScriptOptimizeOn) { - const { - deployUrl, - subresourceIntegrity, - scripts = [], - styles = [], - index, - baseHref, - } = options; - - config.plugins.push( - new IndexHtmlWebpackPlugin({ - indexPath: resolve(wco.root, index), - outputPath: basename(index), - baseHref, - entrypoints: generateEntryPoints({ scripts, styles }), - deployUrl, - sri: subresourceIntegrity, - moduleEntrypoints: [], - noModuleEntrypoints: ['polyfills-es5'], - }) - ); - } - - return config; +function getBrowserPartial(wco: any, options: WebBuildExecutorOptions) { + return getBrowserConfig(wco); } function _getBaseWebpackPartial( - options: WebBuildBuilderOptions, + options: WebBuildExecutorOptions, esm: boolean, isScriptOptimizeOn: boolean, emitDecoratorMetadata: boolean, @@ -300,9 +261,7 @@ export function getPolyfillsPartial( // Safari 10.1 supports