feat(webpack): remove support for legacy browsers (#14190)
This commit is contained in:
parent
716ba89b15
commit
fcc02d1932
@ -37,7 +37,7 @@
|
|||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"skipHelperLibs": {
|
"skipHelperLibs": {
|
||||||
"description": "Do not install helpers libs (tslib, core-js, regenerator-runtime).",
|
"description": "Do not install tslib.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"hidden": true
|
"hidden": true
|
||||||
|
|||||||
@ -300,10 +300,6 @@
|
|||||||
"description": "Extract CSS into a `.css` file.",
|
"description": "Extract CSS into a `.css` file.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
"es2015Polyfills": {
|
|
||||||
"description": "Conditional polyfills loaded in browsers which do not support `ES2015`.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"subresourceIntegrity": {
|
"subresourceIntegrity": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Enables the use of subresource integrity validation.",
|
"description": "Enables the use of subresource integrity validation.",
|
||||||
|
|||||||
@ -307,10 +307,6 @@
|
|||||||
"description": "Extract CSS into a `.css` file.",
|
"description": "Extract CSS into a `.css` file.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
"es2015Polyfills": {
|
|
||||||
"description": "Conditional polyfills loaded in browsers which do not support `ES2015`.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"subresourceIntegrity": {
|
"subresourceIntegrity": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Enables the use of subresource integrity validation.",
|
"description": "Enables the use of subresource integrity validation.",
|
||||||
|
|||||||
@ -597,7 +597,6 @@ describe('Nx Affected and Graph Tests', () => {
|
|||||||
expect(() => checkFilesExist('project-graph.html')).not.toThrow();
|
expect(() => checkFilesExist('project-graph.html')).not.toThrow();
|
||||||
expect(() => checkFilesExist('static/styles.css')).not.toThrow();
|
expect(() => checkFilesExist('static/styles.css')).not.toThrow();
|
||||||
expect(() => checkFilesExist('static/runtime.js')).not.toThrow();
|
expect(() => checkFilesExist('static/runtime.js')).not.toThrow();
|
||||||
expect(() => checkFilesExist('static/polyfills.js')).not.toThrow();
|
|
||||||
expect(() => checkFilesExist('static/main.js')).not.toThrow();
|
expect(() => checkFilesExist('static/main.js')).not.toThrow();
|
||||||
expect(() => checkFilesExist('static/environment.js')).not.toThrow();
|
expect(() => checkFilesExist('static/environment.js')).not.toThrow();
|
||||||
|
|
||||||
|
|||||||
@ -26,10 +26,7 @@ describe('file-server', () => {
|
|||||||
const p = await runCommandUntil(
|
const p = await runCommandUntil(
|
||||||
`serve ${appName} --port=${port}`,
|
`serve ${appName} --port=${port}`,
|
||||||
(output) => {
|
(output) => {
|
||||||
return (
|
return output.indexOf(`localhost:${port}`) > -1;
|
||||||
output.indexOf('webpack compiled') > -1 &&
|
|
||||||
output.indexOf(`localhost:${port}`) > -1
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -39,5 +36,5 @@ describe('file-server', () => {
|
|||||||
} catch {
|
} catch {
|
||||||
// ignore
|
// ignore
|
||||||
}
|
}
|
||||||
}, 1000000);
|
}, 300_000);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -112,23 +112,6 @@ describe('Web Components Applications', () => {
|
|||||||
checkFilesExist(`dist/libs/${libName}/_should_keep.txt`);
|
checkFilesExist(`dist/libs/${libName}/_should_keep.txt`);
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
it('should do another build if differential loading is needed', async () => {
|
|
||||||
const appName = uniq('app');
|
|
||||||
|
|
||||||
runCLI(
|
|
||||||
`generate @nrwl/web:app ${appName} --bundler=webpack --no-interactive`
|
|
||||||
);
|
|
||||||
|
|
||||||
updateFile(`apps/${appName}/browserslist`, `IE 9-11`);
|
|
||||||
|
|
||||||
runCLI(`build ${appName} --outputHashing=none`);
|
|
||||||
|
|
||||||
checkFilesExist(
|
|
||||||
`dist/apps/${appName}/main.js`,
|
|
||||||
`dist/apps/${appName}/main.es5.js`
|
|
||||||
);
|
|
||||||
}, 120000);
|
|
||||||
|
|
||||||
it('should emit decorator metadata when it is enabled in tsconfig', async () => {
|
it('should emit decorator metadata when it is enabled in tsconfig', async () => {
|
||||||
const appName = uniq('app');
|
const appName = uniq('app');
|
||||||
runCLI(
|
runCLI(
|
||||||
|
|||||||
@ -222,7 +222,6 @@ function buildTargetWebpack(
|
|||||||
const defaultWebpack = getWebpackConfig(
|
const defaultWebpack = getWebpackConfig(
|
||||||
context,
|
context,
|
||||||
options,
|
options,
|
||||||
true,
|
|
||||||
isScriptOptimizeOn,
|
isScriptOptimizeOn,
|
||||||
{
|
{
|
||||||
root: ctProjectConfig.root,
|
root: ctProjectConfig.root,
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ExecutorContext,
|
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
logger,
|
logger,
|
||||||
ProjectGraph,
|
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
readNxJson,
|
|
||||||
TargetConfiguration,
|
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
} from '@nrwl/devkit';
|
} from '@nrwl/devkit';
|
||||||
import { getBaseWebpackPartial } from '@nrwl/webpack/src/utils/config';
|
import { getBaseWebpackPartial } from '@nrwl/webpack/src/utils/config';
|
||||||
@ -17,7 +13,6 @@ import { gte } from 'semver';
|
|||||||
import { Configuration, DefinePlugin, WebpackPluginInstance } from 'webpack';
|
import { Configuration, DefinePlugin, WebpackPluginInstance } from 'webpack';
|
||||||
import * as mergeWebpack from 'webpack-merge';
|
import * as mergeWebpack from 'webpack-merge';
|
||||||
import { mergePlugins } from './merge-plugins';
|
import { mergePlugins } from './merge-plugins';
|
||||||
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
|
|
||||||
|
|
||||||
const reactWebpackConfig = require('../webpack');
|
const reactWebpackConfig = require('../webpack');
|
||||||
|
|
||||||
@ -119,14 +114,12 @@ export const webpack = async (
|
|||||||
target: 'web',
|
target: 'web',
|
||||||
};
|
};
|
||||||
|
|
||||||
const esm = true;
|
|
||||||
const isScriptOptimizeOn = storybookWebpackConfig.mode !== 'development';
|
const isScriptOptimizeOn = storybookWebpackConfig.mode !== 'development';
|
||||||
const extractCss = storybookWebpackConfig.mode === 'production';
|
const extractCss = storybookWebpackConfig.mode === 'production';
|
||||||
|
|
||||||
// ESM build for modern browsers.
|
// ESM build for modern browsers.
|
||||||
const baseWebpackConfig = mergeWebpack.merge([
|
const baseWebpackConfig = mergeWebpack.merge([
|
||||||
getBaseWebpackPartial(builderOptions, {
|
getBaseWebpackPartial(builderOptions, {
|
||||||
esm,
|
|
||||||
isScriptOptimizeOn,
|
isScriptOptimizeOn,
|
||||||
skipTypeCheck: true,
|
skipTypeCheck: true,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -73,7 +73,6 @@ describe('app', () => {
|
|||||||
await applicationGenerator(appTree, schema);
|
await applicationGenerator(appTree, schema);
|
||||||
|
|
||||||
expect(appTree.exists('apps/my-app/.babelrc')).toBeTruthy();
|
expect(appTree.exists('apps/my-app/.babelrc')).toBeTruthy();
|
||||||
expect(appTree.exists('apps/my-app/.browserslistrc')).toBeTruthy();
|
|
||||||
expect(appTree.exists('apps/my-app/src/main.tsx')).toBeTruthy();
|
expect(appTree.exists('apps/my-app/src/main.tsx')).toBeTruthy();
|
||||||
expect(appTree.exists('apps/my-app/src/app/app.tsx')).toBeTruthy();
|
expect(appTree.exists('apps/my-app/src/app/app.tsx')).toBeTruthy();
|
||||||
expect(appTree.exists('apps/my-app/src/app/app.spec.tsx')).toBeTruthy();
|
expect(appTree.exists('apps/my-app/src/app/app.spec.tsx')).toBeTruthy();
|
||||||
@ -312,7 +311,6 @@ describe('app', () => {
|
|||||||
main: 'apps/my-app/src/main.tsx',
|
main: 'apps/my-app/src/main.tsx',
|
||||||
baseHref: '/',
|
baseHref: '/',
|
||||||
outputPath: 'dist/apps/my-app',
|
outputPath: 'dist/apps/my-app',
|
||||||
polyfills: 'apps/my-app/src/polyfills.ts',
|
|
||||||
scripts: [],
|
scripts: [],
|
||||||
styles: ['apps/my-app/src/styles.css'],
|
styles: ['apps/my-app/src/styles.css'],
|
||||||
tsConfig: 'apps/my-app/tsconfig.app.json',
|
tsConfig: 'apps/my-app/tsconfig.app.json',
|
||||||
@ -810,19 +808,6 @@ describe('app', () => {
|
|||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add required polyfills for core-js and regenerator', async () => {
|
|
||||||
await applicationGenerator(appTree, {
|
|
||||||
...schema,
|
|
||||||
});
|
|
||||||
|
|
||||||
const polyfillsSource = appTree
|
|
||||||
.read('apps/my-app/src/polyfills.ts')
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
expect(polyfillsSource).toContain('regenerator');
|
|
||||||
expect(polyfillsSource).toContain('core-js');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('--skipWorkspaceJson', () => {
|
describe('--skipWorkspaceJson', () => {
|
||||||
it('should update workspace with defaults when --skipWorkspaceJson=false', async () => {
|
it('should update workspace with defaults when --skipWorkspaceJson=false', async () => {
|
||||||
await applicationGenerator(appTree, {
|
await applicationGenerator(appTree, {
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
# This file is used by:
|
|
||||||
# 1. autoprefixer to adjust CSS to support the below specified browsers
|
|
||||||
# 2. babel preset-env to adjust included polyfills
|
|
||||||
#
|
|
||||||
# For additional information regarding the format and rule options, please see:
|
|
||||||
# https://github.com/browserslist/browserslist#queries
|
|
||||||
#
|
|
||||||
# If you need to support different browsers in production, you may tweak the list below.
|
|
||||||
|
|
||||||
last 1 Chrome version
|
|
||||||
last 1 Firefox version
|
|
||||||
last 2 Edge major versions
|
|
||||||
last 2 Safari major version
|
|
||||||
last 2 iOS major versions
|
|
||||||
Firefox ESR
|
|
||||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
* Polyfill stable language features. These imports will be optimized by `@babel/preset-env`.
|
|
||||||
*
|
|
||||||
* See: https://github.com/zloirock/core-js#babel
|
|
||||||
*/
|
|
||||||
import 'core-js/stable';
|
|
||||||
import 'regenerator-runtime/runtime';
|
|
||||||
@ -57,10 +57,6 @@ function createBuildTarget(options: NormalizedSchema): TargetConfiguration {
|
|||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
maybeJs(options, `src/main.tsx`)
|
maybeJs(options, `src/main.tsx`)
|
||||||
),
|
),
|
||||||
polyfills: joinPathFragments(
|
|
||||||
options.appProjectRoot,
|
|
||||||
maybeJs(options, 'src/polyfills.ts')
|
|
||||||
),
|
|
||||||
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
assets: [
|
assets: [
|
||||||
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
|
joinPathFragments(options.appProjectRoot, 'src/favicon.ico'),
|
||||||
|
|||||||
@ -52,8 +52,6 @@ function updateDependencies(host: Tree, schema: InitSchema) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!schema.skipHelperLibs) {
|
if (!schema.skipHelperLibs) {
|
||||||
dependencies['core-js'] = '^3.6.5';
|
|
||||||
dependencies['regenerator-runtime'] = '0.13.7';
|
|
||||||
dependencies['tslib'] = tsLibVersion;
|
dependencies['tslib'] = tsLibVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -34,7 +34,7 @@
|
|||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"skipHelperLibs": {
|
"skipHelperLibs": {
|
||||||
"description": "Do not install helpers libs (tslib, core-js, regenerator-runtime).",
|
"description": "Do not install tslib.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"hidden": true
|
"hidden": true
|
||||||
|
|||||||
@ -43,7 +43,6 @@ module.exports = function (api: any, options: NxWebBabelPresetOptions = {}) {
|
|||||||
? { targets: { node: 'current' }, loose: true }
|
? { targets: { node: 'current' }, loose: true }
|
||||||
: {
|
: {
|
||||||
// Allow importing core-js in entrypoint and use browserlist to select polyfills.
|
// Allow importing core-js in entrypoint and use browserlist to select polyfills.
|
||||||
// This is needed for differential loading as well.
|
|
||||||
useBuiltIns: options.useBuiltIns ?? 'entry',
|
useBuiltIns: options.useBuiltIns ?? 'entry',
|
||||||
corejs: 3,
|
corejs: 3,
|
||||||
// Do not transform modules to CJS
|
// Do not transform modules to CJS
|
||||||
|
|||||||
@ -176,10 +176,6 @@
|
|||||||
"description": "Extract CSS into a `.css` file.",
|
"description": "Extract CSS into a `.css` file.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
"es2015Polyfills": {
|
|
||||||
"description": "Conditional polyfills loaded in browsers which do not support `ES2015`.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"subresourceIntegrity": {
|
"subresourceIntegrity": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Enables the use of subresource integrity validation.",
|
"description": "Enables the use of subresource integrity validation.",
|
||||||
|
|||||||
@ -348,7 +348,6 @@ describe('app', () => {
|
|||||||
baseHref: '/',
|
baseHref: '/',
|
||||||
main: 'apps/my-app/src/main.ts',
|
main: 'apps/my-app/src/main.ts',
|
||||||
outputPath: 'dist/apps/my-app',
|
outputPath: 'dist/apps/my-app',
|
||||||
polyfills: 'apps/my-app/src/polyfills.ts',
|
|
||||||
scripts: [],
|
scripts: [],
|
||||||
styles: ['apps/my-app/src/styles.css'],
|
styles: ['apps/my-app/src/styles.css'],
|
||||||
tsConfig: 'apps/my-app/tsconfig.app.json',
|
tsConfig: 'apps/my-app/tsconfig.app.json',
|
||||||
|
|||||||
@ -91,10 +91,6 @@ async function setupBundler(tree: Tree, options: NormalizedSchema) {
|
|||||||
'src/index.html'
|
'src/index.html'
|
||||||
);
|
);
|
||||||
buildOptions.baseHref = '/';
|
buildOptions.baseHref = '/';
|
||||||
buildOptions.polyfills = joinPathFragments(
|
|
||||||
options.appProjectRoot,
|
|
||||||
'src/polyfills.ts'
|
|
||||||
);
|
|
||||||
buildOptions.styles = [
|
buildOptions.styles = [
|
||||||
joinPathFragments(options.appProjectRoot, `src/styles.${options.style}`),
|
joinPathFragments(options.appProjectRoot, `src/styles.${options.style}`),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
/**
|
|
||||||
* Polyfill stable language features. These imports will be optimized by `@babel/preset-env`.
|
|
||||||
*
|
|
||||||
* See: https://github.com/zloirock/core-js#babel
|
|
||||||
*/
|
|
||||||
import 'core-js/stable';
|
|
||||||
import 'regenerator-runtime/runtime';
|
|
||||||
@ -7,5 +7,11 @@
|
|||||||
"factory": "./src/migrations/update-15-0-0/add-babel-inputs"
|
"factory": "./src/migrations/update-15-0-0/add-babel-inputs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"remove-es2015-polyfills-option": {
|
||||||
|
"cli": "nx",
|
||||||
|
"version": "15.4.5-beta.0",
|
||||||
|
"description": "Removes es2015Polyfills option since legacy browsers are no longer supported.",
|
||||||
|
"factory": "./src/migrations/update-15-4-5/remove-es2015-polyfills-option"
|
||||||
|
},
|
||||||
"packageJsonUpdates": {}
|
"packageJsonUpdates": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,8 +34,6 @@
|
|||||||
"@nrwl/workspace": "file:../workspace",
|
"@nrwl/workspace": "file:../workspace",
|
||||||
"autoprefixer": "^10.4.9",
|
"autoprefixer": "^10.4.9",
|
||||||
"babel-loader": "^8.2.2",
|
"babel-loader": "^8.2.2",
|
||||||
"browserslist": "^4.21.4",
|
|
||||||
"caniuse-lite": "^1.0.30001394",
|
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"copy-webpack-plugin": "^10.2.4",
|
"copy-webpack-plugin": "^10.2.4",
|
||||||
|
|||||||
@ -23,7 +23,6 @@ export function getDevServerConfig(
|
|||||||
const webpackConfig = getWebpackConfig(
|
const webpackConfig = getWebpackConfig(
|
||||||
context,
|
context,
|
||||||
buildOptions,
|
buildOptions,
|
||||||
true,
|
|
||||||
typeof buildOptions.optimization === 'boolean'
|
typeof buildOptions.optimization === 'boolean'
|
||||||
? buildOptions.optimization
|
? buildOptions.optimization
|
||||||
: buildOptions.optimization?.scripts
|
: buildOptions.optimization?.scripts
|
||||||
@ -53,7 +52,6 @@ export function getDevServerConfig(
|
|||||||
deployUrl,
|
deployUrl,
|
||||||
sri: subresourceIntegrity,
|
sri: subresourceIntegrity,
|
||||||
moduleEntrypoints: [],
|
moduleEntrypoints: [],
|
||||||
noModuleEntrypoints: ['polyfills-es5'],
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { posix, resolve } from 'path';
|
import { posix, resolve } from 'path';
|
||||||
import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
||||||
import { ScriptTarget } from 'typescript';
|
|
||||||
import { getHashDigest, interpolateName } from 'loader-utils';
|
import { getHashDigest, interpolateName } from 'loader-utils';
|
||||||
import type { Configuration } from 'webpack';
|
import type { Configuration } from 'webpack';
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ interface GetWebpackConfigOverrides {
|
|||||||
export function getWebpackConfig(
|
export function getWebpackConfig(
|
||||||
context: ExecutorContext,
|
context: ExecutorContext,
|
||||||
options: NormalizedWebpackExecutorOptions,
|
options: NormalizedWebpackExecutorOptions,
|
||||||
esm?: boolean,
|
|
||||||
isScriptOptimizeOn?: boolean,
|
isScriptOptimizeOn?: boolean,
|
||||||
overrides?: GetWebpackConfigOverrides
|
overrides?: GetWebpackConfigOverrides
|
||||||
): Configuration {
|
): Configuration {
|
||||||
@ -53,19 +51,11 @@ export function getWebpackConfig(
|
|||||||
sourceRoot = project.sourceRoot;
|
sourceRoot = project.sourceRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isScriptOptimizeOn) {
|
|
||||||
// Angular CLI uses an environment variable (NG_BUILD_DIFFERENTIAL_FULL)
|
|
||||||
// to determine whether to use the scriptTargetOverride
|
|
||||||
// or the tsConfig target
|
|
||||||
// We want to force the target if overridden
|
|
||||||
tsConfig.options.target = ScriptTarget.ES5;
|
|
||||||
}
|
|
||||||
const wco: any = {
|
const wco: any = {
|
||||||
root: workspaceRoot,
|
root: workspaceRoot,
|
||||||
projectRoot: resolve(workspaceRoot, projectRoot),
|
projectRoot: resolve(workspaceRoot, projectRoot),
|
||||||
sourceRoot: resolve(workspaceRoot, sourceRoot),
|
sourceRoot: resolve(workspaceRoot, sourceRoot),
|
||||||
buildOptions: convertBuildOptions(options),
|
buildOptions: convertBuildOptions(options),
|
||||||
esm,
|
|
||||||
console,
|
console,
|
||||||
tsConfig,
|
tsConfig,
|
||||||
tsConfigPath: options.tsConfig,
|
tsConfigPath: options.tsConfig,
|
||||||
@ -75,18 +65,12 @@ export function getWebpackConfig(
|
|||||||
_getBaseWebpackPartial(
|
_getBaseWebpackPartial(
|
||||||
context,
|
context,
|
||||||
options,
|
options,
|
||||||
esm,
|
|
||||||
isScriptOptimizeOn,
|
isScriptOptimizeOn,
|
||||||
tsConfig.options.emitDecoratorMetadata,
|
tsConfig.options.emitDecoratorMetadata,
|
||||||
overrides
|
overrides
|
||||||
),
|
),
|
||||||
options.target === 'web'
|
options.target === 'web'
|
||||||
? getPolyfillsPartial(
|
? getPolyfillsPartial(options.polyfills, isScriptOptimizeOn)
|
||||||
options.polyfills,
|
|
||||||
options.es2015Polyfills,
|
|
||||||
esm,
|
|
||||||
isScriptOptimizeOn
|
|
||||||
)
|
|
||||||
: {},
|
: {},
|
||||||
options.target === 'web'
|
options.target === 'web'
|
||||||
? getStylesPartial(
|
? getStylesPartial(
|
||||||
@ -105,7 +89,6 @@ export function getWebpackConfig(
|
|||||||
function _getBaseWebpackPartial(
|
function _getBaseWebpackPartial(
|
||||||
context: ExecutorContext,
|
context: ExecutorContext,
|
||||||
options: NormalizedWebpackExecutorOptions,
|
options: NormalizedWebpackExecutorOptions,
|
||||||
esm: boolean,
|
|
||||||
isScriptOptimizeOn: boolean,
|
isScriptOptimizeOn: boolean,
|
||||||
emitDecoratorMetadata: boolean,
|
emitDecoratorMetadata: boolean,
|
||||||
overrides?: GetWebpackConfigOverrides
|
overrides?: GetWebpackConfigOverrides
|
||||||
@ -113,7 +96,6 @@ function _getBaseWebpackPartial(
|
|||||||
let partial = getBaseWebpackPartial(
|
let partial = getBaseWebpackPartial(
|
||||||
options,
|
options,
|
||||||
{
|
{
|
||||||
esm,
|
|
||||||
isScriptOptimizeOn,
|
isScriptOptimizeOn,
|
||||||
emitDecoratorMetadata,
|
emitDecoratorMetadata,
|
||||||
configuration: overrides?.configuration ?? context.configurationName,
|
configuration: overrides?.configuration ?? context.configurationName,
|
||||||
@ -271,33 +253,23 @@ export function getStylesPartial(
|
|||||||
|
|
||||||
export function getPolyfillsPartial(
|
export function getPolyfillsPartial(
|
||||||
polyfills: string,
|
polyfills: string,
|
||||||
es2015Polyfills: string,
|
|
||||||
esm: boolean,
|
|
||||||
isScriptOptimizeOn: boolean
|
isScriptOptimizeOn: boolean
|
||||||
): Configuration {
|
): Configuration {
|
||||||
const config = {
|
const config = {
|
||||||
entry: {} as { [key: string]: string[] },
|
entry: {} as { [key: string]: string[] },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (polyfills && esm && isScriptOptimizeOn) {
|
if (polyfills && isScriptOptimizeOn) {
|
||||||
// Safari 10.1 supports <script type="module"> but not <script nomodule>.
|
// Safari 10.1 supports <script type="module"> but not <script nomodule>.
|
||||||
// Need to patch it up so the browser doesn't load both sets.
|
// Need to patch it up so the browser doesn't load both sets.
|
||||||
config.entry.polyfills = [
|
config.entry.polyfills = [
|
||||||
require.resolve('@nrwl/webpack/src/utils/webpack/safari-nomodule.js'),
|
require.resolve('@nrwl/webpack/src/utils/webpack/safari-nomodule.js'),
|
||||||
...(polyfills ? [polyfills] : []),
|
...(polyfills ? [polyfills] : []),
|
||||||
];
|
];
|
||||||
} else if (es2015Polyfills && !esm && isScriptOptimizeOn) {
|
|
||||||
config.entry.polyfills = [
|
|
||||||
es2015Polyfills,
|
|
||||||
...(polyfills ? [polyfills] : []),
|
|
||||||
];
|
|
||||||
} else {
|
} else {
|
||||||
if (polyfills) {
|
if (polyfills) {
|
||||||
config.entry.polyfills = [polyfills];
|
config.entry.polyfills = [polyfills];
|
||||||
}
|
}
|
||||||
if (es2015Polyfills) {
|
|
||||||
config.entry['polyfills-es5'] = [es2015Polyfills];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import { normalizePath } from '@nrwl/devkit';
|
|||||||
import type {
|
import type {
|
||||||
AssetGlobPattern,
|
AssetGlobPattern,
|
||||||
FileReplacement,
|
FileReplacement,
|
||||||
WebpackExecutorOptions,
|
|
||||||
NormalizedWebpackExecutorOptions,
|
NormalizedWebpackExecutorOptions,
|
||||||
|
WebpackExecutorOptions,
|
||||||
} from '../schema';
|
} from '../schema';
|
||||||
|
|
||||||
export function normalizeOptions(
|
export function normalizeOptions(
|
||||||
@ -34,11 +34,9 @@ export function normalizeOptions(
|
|||||||
}
|
}
|
||||||
: options.optimization,
|
: options.optimization,
|
||||||
polyfills: options.polyfills ? resolve(root, options.polyfills) : undefined,
|
polyfills: options.polyfills ? resolve(root, options.polyfills) : undefined,
|
||||||
es2015Polyfills: options.es2015Polyfills
|
|
||||||
? resolve(root, options.es2015Polyfills)
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeFileReplacements(
|
function normalizeFileReplacements(
|
||||||
root: string,
|
root: string,
|
||||||
fileReplacements: FileReplacement[]
|
fileReplacements: FileReplacement[]
|
||||||
|
|||||||
@ -47,7 +47,6 @@ export interface WebpackExecutorOptions {
|
|||||||
crossOrigin?: CrossOriginValue;
|
crossOrigin?: CrossOriginValue;
|
||||||
deleteOutputPath?: boolean;
|
deleteOutputPath?: boolean;
|
||||||
deployUrl?: string;
|
deployUrl?: string;
|
||||||
es2015Polyfills?: string;
|
|
||||||
externalDependencies?: 'all' | 'none' | string[];
|
externalDependencies?: 'all' | 'none' | string[];
|
||||||
extractCss?: boolean;
|
extractCss?: boolean;
|
||||||
extractLicenses?: boolean;
|
extractLicenses?: boolean;
|
||||||
|
|||||||
@ -228,10 +228,6 @@
|
|||||||
"description": "Extract CSS into a `.css` file.",
|
"description": "Extract CSS into a `.css` file.",
|
||||||
"default": true
|
"default": true
|
||||||
},
|
},
|
||||||
"es2015Polyfills": {
|
|
||||||
"description": "Conditional polyfills loaded in browsers which do not support `ES2015`.",
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"subresourceIntegrity": {
|
"subresourceIntegrity": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Enables the use of subresource integrity validation.",
|
"description": "Enables the use of subresource integrity validation.",
|
||||||
|
|||||||
@ -1,26 +1,18 @@
|
|||||||
import 'dotenv/config';
|
import 'dotenv/config';
|
||||||
import { ExecutorContext, logger } from '@nrwl/devkit';
|
import { ExecutorContext, logger } from '@nrwl/devkit';
|
||||||
import { eachValueFrom } from '@nrwl/devkit/src/utils/rxjs-for-await';
|
import { eachValueFrom } from '@nrwl/devkit/src/utils/rxjs-for-await';
|
||||||
import type { Configuration, Stats } from 'webpack';
|
import type { Configuration } from 'webpack';
|
||||||
import { from, of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import {
|
import { switchMap, tap } from 'rxjs/operators';
|
||||||
bufferCount,
|
|
||||||
mergeMap,
|
|
||||||
mergeScan,
|
|
||||||
switchMap,
|
|
||||||
tap,
|
|
||||||
} from 'rxjs/operators';
|
|
||||||
import { basename, join, resolve } from 'path';
|
import { basename, join, resolve } from 'path';
|
||||||
import {
|
import {
|
||||||
calculateProjectDependencies,
|
calculateProjectDependencies,
|
||||||
createTmpTsConfig,
|
createTmpTsConfig,
|
||||||
} from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
} from '@nrwl/workspace/src/utilities/buildable-libs-utils';
|
||||||
import { readTsConfig } from '@nrwl/workspace/src/utilities/typescript';
|
|
||||||
|
|
||||||
import { getWebpackConfig } from './lib/get-webpack-config';
|
import { getWebpackConfig } from './lib/get-webpack-config';
|
||||||
import { getEmittedFiles } from './lib/get-emitted-files';
|
import { getEmittedFiles } from './lib/get-emitted-files';
|
||||||
import { runWebpack } from './lib/run-webpack';
|
import { runWebpack } from './lib/run-webpack';
|
||||||
import { BuildBrowserFeatures } from '../../utils/webpack/build-browser-features';
|
|
||||||
import { deleteOutputDir } from '../../utils/fs';
|
import { deleteOutputDir } from '../../utils/fs';
|
||||||
import { writeIndexHtml } from '../../utils/webpack/write-index-html';
|
import { writeIndexHtml } from '../../utils/webpack/write-index-html';
|
||||||
import { resolveCustomWebpackConfig } from '../../utils/webpack/custom-webpack';
|
import { resolveCustomWebpackConfig } from '../../utils/webpack/custom-webpack';
|
||||||
@ -34,7 +26,7 @@ import { EmittedFile } from '../../utils/models';
|
|||||||
async function getWebpackConfigs(
|
async function getWebpackConfigs(
|
||||||
options: NormalizedWebpackExecutorOptions,
|
options: NormalizedWebpackExecutorOptions,
|
||||||
context: ExecutorContext
|
context: ExecutorContext
|
||||||
): Promise<Configuration[]> {
|
): Promise<Configuration> {
|
||||||
const metadata = context.projectsConfigurations.projects[context.projectName];
|
const metadata = context.projectsConfigurations.projects[context.projectName];
|
||||||
const projectRoot = metadata.root;
|
const projectRoot = metadata.root;
|
||||||
const isScriptOptimizeOn =
|
const isScriptOptimizeOn =
|
||||||
@ -43,13 +35,6 @@ async function getWebpackConfigs(
|
|||||||
: options.optimization && options.optimization.scripts
|
: options.optimization && options.optimization.scripts
|
||||||
? options.optimization.scripts
|
? options.optimization.scripts
|
||||||
: false;
|
: false;
|
||||||
const tsConfig = readTsConfig(options.tsConfig);
|
|
||||||
const scriptTarget = tsConfig.options.target;
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
projectRoot,
|
|
||||||
scriptTarget
|
|
||||||
);
|
|
||||||
|
|
||||||
let customWebpack = null;
|
let customWebpack = null;
|
||||||
|
|
||||||
@ -64,19 +49,8 @@ async function getWebpackConfigs(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Promise.all(
|
const config = getWebpackConfig(context, options, isScriptOptimizeOn);
|
||||||
[
|
|
||||||
// ESM build for modern browsers.
|
|
||||||
getWebpackConfig(context, options, true, isScriptOptimizeOn),
|
|
||||||
// ES5 build for legacy browsers.
|
|
||||||
options.target === 'web' &&
|
|
||||||
isScriptOptimizeOn &&
|
|
||||||
buildBrowserFeatures.isDifferentialLoadingNeeded()
|
|
||||||
? getWebpackConfig(context, options, false, isScriptOptimizeOn)
|
|
||||||
: undefined,
|
|
||||||
]
|
|
||||||
.filter(Boolean)
|
|
||||||
.map(async (config) => {
|
|
||||||
if (customWebpack) {
|
if (customWebpack) {
|
||||||
return await customWebpack(config, {
|
return await customWebpack(config, {
|
||||||
options,
|
options,
|
||||||
@ -86,8 +60,6 @@ async function getWebpackConfigs(
|
|||||||
} else {
|
} else {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WebpackExecutorEvent =
|
export type WebpackExecutorEvent =
|
||||||
@ -162,40 +134,26 @@ export async function* webpackExecutor(
|
|||||||
|
|
||||||
const configs = await getWebpackConfigs(options, context);
|
const configs = await getWebpackConfigs(options, context);
|
||||||
return yield* eachValueFrom(
|
return yield* eachValueFrom(
|
||||||
from(configs).pipe(
|
of(configs).pipe(
|
||||||
mergeMap((config) => (Array.isArray(config) ? from(config) : of(config))),
|
switchMap((config) => {
|
||||||
// Run build sequentially and bail when first one fails.
|
|
||||||
mergeScan(
|
|
||||||
(acc, config) => {
|
|
||||||
if (!acc.hasErrors()) {
|
|
||||||
return runWebpack(config).pipe(
|
return runWebpack(config).pipe(
|
||||||
tap((stats) => {
|
tap((stats) => {
|
||||||
console.info(stats.toString(config.stats));
|
console.info(stats.toString());
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
}),
|
||||||
return of();
|
switchMap(async (result) => {
|
||||||
}
|
const success = result && !result.hasErrors();
|
||||||
},
|
const emittedFiles = getEmittedFiles(result);
|
||||||
{ hasErrors: () => false } as Stats,
|
|
||||||
1
|
|
||||||
),
|
|
||||||
// Collect build results as an array.
|
|
||||||
bufferCount(configs.length),
|
|
||||||
switchMap(async ([result1, result2]) => {
|
|
||||||
const success =
|
|
||||||
result1 && !result1.hasErrors() && (!result2 || !result2.hasErrors());
|
|
||||||
const emittedFiles1 = getEmittedFiles(result1);
|
|
||||||
const emittedFiles2 = result2 ? getEmittedFiles(result2) : [];
|
|
||||||
if (options.index && options.generateIndexHtml) {
|
if (options.index && options.generateIndexHtml) {
|
||||||
await writeIndexHtml({
|
await writeIndexHtml({
|
||||||
crossOrigin: options.crossOrigin,
|
crossOrigin: options.crossOrigin,
|
||||||
sri: options.subresourceIntegrity,
|
sri: options.subresourceIntegrity,
|
||||||
outputPath: join(options.outputPath, basename(options.index)),
|
outputPath: join(options.outputPath, basename(options.index)),
|
||||||
indexPath: join(context.root, options.index),
|
indexPath: join(context.root, options.index),
|
||||||
files: emittedFiles1.filter((x) => x.extension === '.css'),
|
files: emittedFiles.filter((x) => x.extension === '.css'),
|
||||||
noModuleFiles: emittedFiles2,
|
noModuleFiles: [],
|
||||||
moduleFiles: emittedFiles1,
|
moduleFiles: emittedFiles,
|
||||||
baseHref: options.baseHref,
|
baseHref: options.baseHref,
|
||||||
deployUrl: options.deployUrl,
|
deployUrl: options.deployUrl,
|
||||||
scripts: options.scripts,
|
scripts: options.scripts,
|
||||||
@ -209,7 +167,7 @@ export async function* webpackExecutor(
|
|||||||
options.outputPath,
|
options.outputPath,
|
||||||
options.outputFileName
|
options.outputFileName
|
||||||
),
|
),
|
||||||
emittedFiles: [...emittedFiles1, ...emittedFiles2],
|
emittedFiles,
|
||||||
options,
|
options,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|||||||
@ -0,0 +1,67 @@
|
|||||||
|
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
|
||||||
|
import {
|
||||||
|
addProjectConfiguration,
|
||||||
|
readProjectConfiguration,
|
||||||
|
Tree,
|
||||||
|
} from '@nrwl/devkit';
|
||||||
|
import update from './remove-es2015-polyfills-option';
|
||||||
|
|
||||||
|
describe('15.4.5 migration (remove es2015-polyfills)', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update all executors using @nrwl/webpack:webpack and es2015Polyfills option', async () => {
|
||||||
|
addProjectConfiguration(tree, 'app1', {
|
||||||
|
root: 'app1',
|
||||||
|
targets: {
|
||||||
|
build: {
|
||||||
|
executor: '@nrwl/webpack:webpack',
|
||||||
|
options: {
|
||||||
|
es2015Polyfills: 'app1/polyfills.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'app2', {
|
||||||
|
root: 'app2',
|
||||||
|
targets: {
|
||||||
|
custom: {
|
||||||
|
executor: '@nrwl/webpack:webpack',
|
||||||
|
options: {
|
||||||
|
es2016Polyfills: 'app2/polyfills.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
addProjectConfiguration(tree, 'app3', {
|
||||||
|
root: 'app3',
|
||||||
|
targets: {
|
||||||
|
custom: {
|
||||||
|
executor: '@foo/bar:faz',
|
||||||
|
options: {
|
||||||
|
es2015Polyfills: 'app3/polyfills.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await update(tree);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(tree, 'app1').targets.build.options
|
||||||
|
.es2015Polyfills
|
||||||
|
).toBeUndefined();
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(tree, 'app2').targets.custom.options
|
||||||
|
.es2015Polyfills
|
||||||
|
).toBeUndefined();
|
||||||
|
// Another executor, left intact.
|
||||||
|
expect(
|
||||||
|
readProjectConfiguration(tree, 'app3').targets.custom.options
|
||||||
|
.es2015Polyfills
|
||||||
|
).toEqual('app3/polyfills.ts');
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { getProjects, Tree, updateProjectConfiguration } from '@nrwl/devkit';
|
||||||
|
|
||||||
|
export default async function (tree: Tree) {
|
||||||
|
const projects = getProjects(tree);
|
||||||
|
projects.forEach((p) => {
|
||||||
|
let shouldUpdate = false;
|
||||||
|
|
||||||
|
Object.entries(p.targets).forEach(([name, config]) => {
|
||||||
|
if (
|
||||||
|
p.targets?.[name]?.executor === '@nrwl/webpack:webpack' &&
|
||||||
|
p.targets?.[name]?.options.es2015Polyfills
|
||||||
|
) {
|
||||||
|
delete p.targets?.[name]?.options.es2015Polyfills;
|
||||||
|
shouldUpdate = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (shouldUpdate) {
|
||||||
|
updateProjectConfiguration(tree, p.name, p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -23,7 +23,6 @@ const IGNORED_WEBPACK_WARNINGS = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
export interface InternalBuildOptions {
|
export interface InternalBuildOptions {
|
||||||
esm?: boolean;
|
|
||||||
isScriptOptimizeOn?: boolean;
|
isScriptOptimizeOn?: boolean;
|
||||||
emitDecoratorMetadata?: boolean;
|
emitDecoratorMetadata?: boolean;
|
||||||
configuration?: string;
|
configuration?: string;
|
||||||
@ -40,18 +39,13 @@ export function getBaseWebpackPartial(
|
|||||||
// If the function is called directly and not through `@nrwl/webpack:webpack` then this target may not be set.
|
// If the function is called directly and not through `@nrwl/webpack:webpack` then this target may not be set.
|
||||||
options.target ??= 'web';
|
options.target ??= 'web';
|
||||||
|
|
||||||
const mainFields = [
|
const mainFields = ['es2015', 'module', 'main'];
|
||||||
...(internalOptions.esm ? ['es2015'] : []),
|
|
||||||
'module',
|
|
||||||
'main',
|
|
||||||
];
|
|
||||||
const hashFormat = getOutputHashFormat(options.outputHashing);
|
const hashFormat = getOutputHashFormat(options.outputHashing);
|
||||||
const suffixFormat = internalOptions.esm ? '' : '.es5';
|
|
||||||
const filename = internalOptions.isScriptOptimizeOn
|
const filename = internalOptions.isScriptOptimizeOn
|
||||||
? `[name]${hashFormat.script}${suffixFormat}.js`
|
? `[name]${hashFormat.script}.js`
|
||||||
: '[name].js';
|
: '[name].js';
|
||||||
const chunkFilename = internalOptions.isScriptOptimizeOn
|
const chunkFilename = internalOptions.isScriptOptimizeOn
|
||||||
? `[name]${hashFormat.chunk}${suffixFormat}.js`
|
? `[name]${hashFormat.chunk}.js`
|
||||||
: '[name].js';
|
: '[name].js';
|
||||||
const mode = internalOptions.isScriptOptimizeOn
|
const mode = internalOptions.isScriptOptimizeOn
|
||||||
? 'production'
|
? 'production'
|
||||||
@ -90,7 +84,7 @@ export function getBaseWebpackPartial(
|
|||||||
hashFunction: 'xxhash64',
|
hashFunction: 'xxhash64',
|
||||||
// Disabled for performance
|
// Disabled for performance
|
||||||
pathinfo: false,
|
pathinfo: false,
|
||||||
scriptType: internalOptions.esm ? 'module' : undefined,
|
scriptType: 'module',
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
// Enabled for performance
|
// Enabled for performance
|
||||||
@ -180,14 +174,21 @@ export function getBaseWebpackPartial(
|
|||||||
webpackConfig.plugins.push(
|
webpackConfig.plugins.push(
|
||||||
new webpack.DefinePlugin(getClientEnvironment(mode).stringified)
|
new webpack.DefinePlugin(getClientEnvironment(mode).stringified)
|
||||||
);
|
);
|
||||||
if (options.compiler !== 'swc' && internalOptions.isScriptOptimizeOn) {
|
webpackConfig.optimization ??= {};
|
||||||
|
webpackConfig.optimization.nodeEnv = process.env.NODE_ENV ?? mode;
|
||||||
|
|
||||||
|
if (internalOptions.isScriptOptimizeOn) {
|
||||||
|
// Always check sideEffects field in package.json for tree-shaking to work.
|
||||||
|
webpackConfig.optimization.sideEffects = true;
|
||||||
|
|
||||||
|
if (options.compiler !== 'swc') {
|
||||||
webpackConfig.optimization = {
|
webpackConfig.optimization = {
|
||||||
sideEffects: true,
|
sideEffects: true,
|
||||||
minimizer: [
|
minimizer: [
|
||||||
new TerserPlugin({
|
new TerserPlugin({
|
||||||
parallel: true,
|
parallel: true,
|
||||||
terserOptions: {
|
terserOptions: {
|
||||||
ecma: (internalOptions.esm ? 2016 : 5) as TerserPlugin.TerserECMA,
|
ecma: 2020,
|
||||||
safari10: true,
|
safari10: true,
|
||||||
output: {
|
output: {
|
||||||
ascii_only: true,
|
ascii_only: true,
|
||||||
@ -200,13 +201,12 @@ export function getBaseWebpackPartial(
|
|||||||
runtimeChunk: true,
|
runtimeChunk: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
webpackConfig.optimization ??= {};
|
}
|
||||||
webpackConfig.optimization.nodeEnv = process.env.NODE_ENV ?? mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const extraPlugins: WebpackPluginInstance[] = [];
|
const extraPlugins: WebpackPluginInstance[] = [];
|
||||||
|
|
||||||
if (!internalOptions.skipTypeCheck && internalOptions.esm) {
|
if (!internalOptions.skipTypeCheck) {
|
||||||
extraPlugins.push(
|
extraPlugins.push(
|
||||||
new ForkTsCheckerWebpackPlugin({
|
new ForkTsCheckerWebpackPlugin({
|
||||||
typescript: {
|
typescript: {
|
||||||
@ -412,7 +412,7 @@ export function createLoaderFromCompiler(
|
|||||||
rootMode: 'upward',
|
rootMode: 'upward',
|
||||||
cwd: join(options.root, options.sourceRoot),
|
cwd: join(options.root, options.sourceRoot),
|
||||||
emitDecoratorMetadata: extraOptions.emitDecoratorMetadata,
|
emitDecoratorMetadata: extraOptions.emitDecoratorMetadata,
|
||||||
isModern: extraOptions.esm,
|
isModern: true,
|
||||||
envName: extraOptions.isScriptOptimizeOn
|
envName: extraOptions.isScriptOptimizeOn
|
||||||
? 'production'
|
? 'production'
|
||||||
: extraOptions.configuration,
|
: extraOptions.configuration,
|
||||||
|
|||||||
@ -25,5 +25,4 @@ export interface CreateWebpackConfigOptions<T = any> {
|
|||||||
buildOptions: T;
|
buildOptions: T;
|
||||||
tsConfig: any;
|
tsConfig: any;
|
||||||
tsConfigPath: string;
|
tsConfigPath: string;
|
||||||
supportES2015: boolean;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,161 +0,0 @@
|
|||||||
import { fs, vol } from 'memfs';
|
|
||||||
jest.mock('fs', () => fs);
|
|
||||||
import { ScriptTarget } from 'typescript';
|
|
||||||
|
|
||||||
// Disable browserslist cache so that each test resolves a new config.
|
|
||||||
process.env.BROWSERSLIST_DISABLE_CACHE = 'true';
|
|
||||||
|
|
||||||
import { BuildBrowserFeatures } from './build-browser-features';
|
|
||||||
|
|
||||||
describe('BuildBrowserFeatures', () => {
|
|
||||||
beforeEach(async () => {
|
|
||||||
vol.fromJSON(
|
|
||||||
{
|
|
||||||
'.browserslistrc': '',
|
|
||||||
},
|
|
||||||
'/root'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isDifferentialLoadingNeeded', () => {
|
|
||||||
it('should be true for for IE 9-11 and ES2015', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'IE 9-11');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isDifferentialLoadingNeeded()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false for Chrome and ES2015', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'last 1 chrome version');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isDifferentialLoadingNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('detects no need for differential loading for target is ES5', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'last 1 chrome version');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES5
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isDifferentialLoadingNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false for Safari 10.1 when target is ES2015', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari 10.1');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isDifferentialLoadingNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isFeatureSupported', () => {
|
|
||||||
it('should be true for es6-module and Safari 10.1', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari 10.1');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isFeatureSupported('es6-module')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false for es6-module and IE9', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'IE 9');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isFeatureSupported('es6-module')).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be true for es6-module and last 1 chrome version', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'last 1 chrome version');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isFeatureSupported('es6-module')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be true for es6-module and Edge 18', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Edge 18');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isFeatureSupported('es6-module')).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('isNoModulePolyfillNeeded', () => {
|
|
||||||
it('should be false for Safari 10.1 when target is ES5', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari 10.1');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES5
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isNoModulePolyfillNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false for Safari 10.1 when target is ES2015', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari 10.1');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isNoModulePolyfillNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be true for Safari 9+ when target is ES2015', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari >= 9');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isNoModulePolyfillNeeded()).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false for Safari 9+ when target is ES5', () => {
|
|
||||||
fs.writeFileSync('/root/.browserslistrc', 'Safari >= 9');
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES5
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isNoModulePolyfillNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be false when not supporting Safari 10.1 target is ES2015', () => {
|
|
||||||
fs.writeFileSync(
|
|
||||||
'/root/.browserslistrc',
|
|
||||||
`
|
|
||||||
Edge 18
|
|
||||||
IE 9
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
'/root',
|
|
||||||
ScriptTarget.ES2015
|
|
||||||
);
|
|
||||||
expect(buildBrowserFeatures.isNoModulePolyfillNeeded()).toBe(false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -1,78 +0,0 @@
|
|||||||
import * as browserslist from 'browserslist';
|
|
||||||
import { feature, features } from 'caniuse-lite';
|
|
||||||
import * as ts from 'typescript';
|
|
||||||
|
|
||||||
export class BuildBrowserFeatures {
|
|
||||||
private readonly _supportedBrowsers: string[];
|
|
||||||
private readonly _es6TargetOrLater: boolean;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private projectRoot: string,
|
|
||||||
private scriptTarget: ts.ScriptTarget
|
|
||||||
) {
|
|
||||||
this._supportedBrowsers = browserslist(undefined, {
|
|
||||||
path: this.projectRoot,
|
|
||||||
});
|
|
||||||
this._es6TargetOrLater = this.scriptTarget > ts.ScriptTarget.ES5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True, when one or more browsers requires ES5
|
|
||||||
* support and the script target is ES2015 or greater.
|
|
||||||
*/
|
|
||||||
isDifferentialLoadingNeeded(): boolean {
|
|
||||||
return this._es6TargetOrLater && this.isEs5SupportNeeded();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True, when one or more browsers requires ES5 support
|
|
||||||
*/
|
|
||||||
isEs5SupportNeeded(): boolean {
|
|
||||||
return !this.isFeatureSupported('es6-module');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Safari 10.1 and iOS Safari 10.3 supports modules,
|
|
||||||
* but does not support the `nomodule` attribute.
|
|
||||||
* While return `true`, when support for Safari 10.1 and iOS Safari 10.3
|
|
||||||
* is required and in differential loading is enabled.
|
|
||||||
*/
|
|
||||||
isNoModulePolyfillNeeded(): boolean {
|
|
||||||
if (!this.isDifferentialLoadingNeeded()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const safariBrowsers = ['safari 10.1', 'ios_saf 10.3'];
|
|
||||||
|
|
||||||
return this._supportedBrowsers.some((browser) =>
|
|
||||||
safariBrowsers.includes(browser)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* True, when a browser feature is supported partially or fully.
|
|
||||||
*/
|
|
||||||
isFeatureSupported(featureId: string): boolean {
|
|
||||||
// y: feature is fully available
|
|
||||||
// n: feature is unavailable
|
|
||||||
// a: feature is partially supported
|
|
||||||
// x: feature is prefixed
|
|
||||||
const criteria = ['y', 'a'];
|
|
||||||
|
|
||||||
const data = feature(features[featureId]);
|
|
||||||
|
|
||||||
return !this._supportedBrowsers.some((browser) => {
|
|
||||||
const [agentId, version] = browser.split(' ');
|
|
||||||
|
|
||||||
const browserData = data.stats[agentId];
|
|
||||||
const featureStatus = (browserData && browserData[version]) as
|
|
||||||
| string
|
|
||||||
| undefined;
|
|
||||||
|
|
||||||
// We are only interested in the first character
|
|
||||||
// Ex: when 'a #4 #5', we only need to check for 'a'
|
|
||||||
// as for such cases we should polyfill these features as needed
|
|
||||||
return !featureStatus || !criteria.includes(featureStatus.charAt(0));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -22,9 +22,7 @@ export function generateEntryPoints(appConfig: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const entryPoints = [
|
const entryPoints = [
|
||||||
'polyfills-nomodule-es5',
|
|
||||||
'runtime',
|
'runtime',
|
||||||
'polyfills-es5',
|
|
||||||
'polyfills',
|
'polyfills',
|
||||||
'sw-register',
|
'sw-register',
|
||||||
...extraEntryPoints(appConfig.styles, 'styles'),
|
...extraEntryPoints(appConfig.styles, 'styles'),
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { CreateWebpackConfigOptions } from '../../models';
|
|||||||
import CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
import CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
|
|
||||||
export function getBrowserConfig(wco: CreateWebpackConfigOptions) {
|
export function getBrowserConfig(wco: CreateWebpackConfigOptions) {
|
||||||
const { buildOptions, supportES2015 } = wco;
|
const { buildOptions } = wco;
|
||||||
const extraPlugins = [];
|
const extraPlugins = [];
|
||||||
|
|
||||||
const stylesOptimization =
|
const stylesOptimization =
|
||||||
@ -41,12 +41,7 @@ export function getBrowserConfig(wco: CreateWebpackConfigOptions) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
resolve: {
|
resolve: {
|
||||||
mainFields: [
|
mainFields: ['browser', 'module', 'main'],
|
||||||
...(supportES2015 ? ['es2015'] : []),
|
|
||||||
'browser',
|
|
||||||
'module',
|
|
||||||
'main',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
crossOriginLoading: buildOptions.subresourceIntegrity
|
crossOriginLoading: buildOptions.subresourceIntegrity
|
||||||
|
|||||||
@ -1,19 +1,17 @@
|
|||||||
import { basename, join, resolve } from 'path';
|
import { basename, resolve } from 'path';
|
||||||
import type { Compiler, Configuration } from 'webpack';
|
import type { Compiler, Configuration } from 'webpack';
|
||||||
import { ids, ProgressPlugin, sources } from 'webpack';
|
import { ProgressPlugin, sources } from 'webpack';
|
||||||
import { ScriptTarget } from 'typescript';
|
|
||||||
|
|
||||||
import { normalizeExtraEntryPoints } from '../normalize-entry';
|
import { normalizeExtraEntryPoints } from '../normalize-entry';
|
||||||
import { ScriptsWebpackPlugin } from '../plugins/scripts-webpack-plugin';
|
import { ScriptsWebpackPlugin } from '../plugins/scripts-webpack-plugin';
|
||||||
import { BuildBrowserFeatures } from '../build-browser-features';
|
|
||||||
import { getOutputHashFormat } from '../../hash-format';
|
import { getOutputHashFormat } from '../../hash-format';
|
||||||
import { findAllNodeModules, findUp } from '../../fs';
|
import { findAllNodeModules, findUp } from '../../fs';
|
||||||
import type { CreateWebpackConfigOptions, ExtraEntryPoint } from '../../models';
|
import type { CreateWebpackConfigOptions } from '../../models';
|
||||||
|
|
||||||
export function getCommonConfig(
|
export function getCommonConfig(
|
||||||
wco: CreateWebpackConfigOptions
|
wco: CreateWebpackConfigOptions
|
||||||
): Configuration {
|
): Configuration {
|
||||||
const { root, projectRoot, sourceRoot, buildOptions, tsConfig } = wco;
|
const { root, projectRoot, sourceRoot, buildOptions } = wco;
|
||||||
|
|
||||||
let stylesOptimization: boolean;
|
let stylesOptimization: boolean;
|
||||||
let scriptsOptimization: boolean;
|
let scriptsOptimization: boolean;
|
||||||
@ -37,48 +35,6 @@ export function getCommonConfig(
|
|||||||
entryPoints['main'] = [resolve(root, buildOptions.main)];
|
entryPoints['main'] = [resolve(root, buildOptions.main)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildBrowserFeatures = new BuildBrowserFeatures(
|
|
||||||
projectRoot,
|
|
||||||
tsConfig.options.target || ScriptTarget.ES5
|
|
||||||
);
|
|
||||||
|
|
||||||
const differentialLoadingNeeded =
|
|
||||||
buildBrowserFeatures.isDifferentialLoadingNeeded();
|
|
||||||
|
|
||||||
if (tsConfig.options.target === ScriptTarget.ES5) {
|
|
||||||
if (buildBrowserFeatures.isEs5SupportNeeded()) {
|
|
||||||
// The nomodule polyfill needs to be inject prior to any script and be
|
|
||||||
// outside of webpack compilation because otherwise webpack will cause the
|
|
||||||
// script to be wrapped in window["webpackJsonp"] which causes this to fail.
|
|
||||||
if (buildBrowserFeatures.isNoModulePolyfillNeeded()) {
|
|
||||||
const noModuleScript: ExtraEntryPoint = {
|
|
||||||
bundleName: 'polyfills-nomodule-es5',
|
|
||||||
input: join(__dirname, '..', 'safari-nomodule.js'),
|
|
||||||
};
|
|
||||||
buildOptions.scripts = buildOptions.scripts
|
|
||||||
? [...buildOptions.scripts, noModuleScript]
|
|
||||||
: [noModuleScript];
|
|
||||||
}
|
|
||||||
|
|
||||||
// For full build differential loading we don't need to generate a seperate polyfill file
|
|
||||||
// because they will be loaded exclusivly based on module and nomodule
|
|
||||||
const polyfillsChunkName = differentialLoadingNeeded
|
|
||||||
? 'polyfills'
|
|
||||||
: 'polyfills-es5';
|
|
||||||
|
|
||||||
entryPoints[polyfillsChunkName] = [
|
|
||||||
join(__dirname, '..', 'es5-polyfills.js'),
|
|
||||||
];
|
|
||||||
|
|
||||||
// If not performing a full differential build the polyfills need to be added to ES5 bundle
|
|
||||||
if (buildOptions.polyfills) {
|
|
||||||
entryPoints[polyfillsChunkName].push(
|
|
||||||
resolve(root, buildOptions.polyfills)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildOptions.polyfills) {
|
if (buildOptions.polyfills) {
|
||||||
entryPoints['polyfills'] = [
|
entryPoints['polyfills'] = [
|
||||||
...(entryPoints['polyfills'] || []),
|
...(entryPoints['polyfills'] || []),
|
||||||
@ -179,26 +135,12 @@ export function getCommonConfig(
|
|||||||
const loaderNodeModules = findAllNodeModules(__dirname, projectRoot);
|
const loaderNodeModules = findAllNodeModules(__dirname, projectRoot);
|
||||||
loaderNodeModules.unshift('node_modules');
|
loaderNodeModules.unshift('node_modules');
|
||||||
|
|
||||||
// Load rxjs path aliases.
|
|
||||||
// https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md#build-and-treeshaking
|
|
||||||
let alias = {};
|
|
||||||
try {
|
|
||||||
const rxjsPathMappingImport = wco.supportES2015
|
|
||||||
? 'rxjs/_esm2015/path-mapping'
|
|
||||||
: 'rxjs/_esm5/path-mapping';
|
|
||||||
const rxPaths = require(require.resolve(rxjsPathMappingImport, {
|
|
||||||
paths: [projectRoot],
|
|
||||||
}));
|
|
||||||
alias = rxPaths(nodeModules);
|
|
||||||
} catch {}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
profile: buildOptions.statsJson,
|
profile: buildOptions.statsJson,
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.ts', '.tsx', '.mjs', '.js'],
|
extensions: ['.ts', '.tsx', '.mjs', '.js'],
|
||||||
symlinks: true,
|
symlinks: true,
|
||||||
modules: [wco.tsConfig.options.baseUrl || projectRoot, 'node_modules'],
|
modules: [wco.tsConfig.options.baseUrl || projectRoot, 'node_modules'],
|
||||||
alias,
|
|
||||||
},
|
},
|
||||||
resolveLoader: {
|
resolveLoader: {
|
||||||
modules: loaderNodeModules,
|
modules: loaderNodeModules,
|
||||||
|
|||||||
@ -21,7 +21,6 @@ export interface IndexHtmlGeneratorProcessOptions {
|
|||||||
baseHref?: string | undefined;
|
baseHref?: string | undefined;
|
||||||
outputPath: string;
|
outputPath: string;
|
||||||
files: FileInfo[];
|
files: FileInfo[];
|
||||||
noModuleFiles: FileInfo[];
|
|
||||||
moduleFiles: FileInfo[];
|
moduleFiles: FileInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,14 +110,7 @@ function augmentIndexHtmlPlugin(
|
|||||||
} = generator.options;
|
} = generator.options;
|
||||||
|
|
||||||
return async (html, options) => {
|
return async (html, options) => {
|
||||||
const {
|
const { lang, baseHref, outputPath = '', files, moduleFiles } = options;
|
||||||
lang,
|
|
||||||
baseHref,
|
|
||||||
outputPath = '',
|
|
||||||
noModuleFiles,
|
|
||||||
files,
|
|
||||||
moduleFiles,
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
return augmentIndexHtml({
|
return augmentIndexHtml({
|
||||||
html,
|
html,
|
||||||
@ -130,7 +122,6 @@ function augmentIndexHtmlPlugin(
|
|||||||
entrypoints,
|
entrypoints,
|
||||||
loadOutputFile: (filePath) =>
|
loadOutputFile: (filePath) =>
|
||||||
generator.readAsset(join(outputPath, filePath)),
|
generator.readAsset(join(outputPath, filePath)),
|
||||||
noModuleFiles,
|
|
||||||
moduleFiles,
|
moduleFiles,
|
||||||
files,
|
files,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -13,7 +13,6 @@ export interface IndexHtmlWebpackPluginOptions
|
|||||||
IndexHtmlGeneratorProcessOptions,
|
IndexHtmlGeneratorProcessOptions,
|
||||||
'files' | 'noModuleFiles' | 'moduleFiles'
|
'files' | 'noModuleFiles' | 'moduleFiles'
|
||||||
> {
|
> {
|
||||||
noModuleEntrypoints: string[];
|
|
||||||
moduleEntrypoints: string[];
|
moduleEntrypoints: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +58,6 @@ export class IndexHtmlWebpackPlugin extends IndexHtmlGenerator {
|
|||||||
const callback = async (assets: Record<string, unknown>) => {
|
const callback = async (assets: Record<string, unknown>) => {
|
||||||
// Get all files for selected entrypoints
|
// Get all files for selected entrypoints
|
||||||
const files: FileInfo[] = [];
|
const files: FileInfo[] = [];
|
||||||
const noModuleFiles: FileInfo[] = [];
|
|
||||||
const moduleFiles: FileInfo[] = [];
|
const moduleFiles: FileInfo[] = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -79,9 +77,7 @@ export class IndexHtmlWebpackPlugin extends IndexHtmlGenerator {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.noModuleEntrypoints.includes(entryName)) {
|
if (this.options.moduleEntrypoints.includes(entryName)) {
|
||||||
noModuleFiles.push(...entryFiles);
|
|
||||||
} else if (this.options.moduleEntrypoints.includes(entryName)) {
|
|
||||||
moduleFiles.push(...entryFiles);
|
moduleFiles.push(...entryFiles);
|
||||||
} else {
|
} else {
|
||||||
files.push(...entryFiles);
|
files.push(...entryFiles);
|
||||||
@ -90,7 +86,6 @@ export class IndexHtmlWebpackPlugin extends IndexHtmlGenerator {
|
|||||||
|
|
||||||
const { content, warnings, errors } = await this.process({
|
const { content, warnings, errors } = await this.process({
|
||||||
files,
|
files,
|
||||||
noModuleFiles,
|
|
||||||
moduleFiles,
|
moduleFiles,
|
||||||
outputPath: dirname(this.options.outputPath),
|
outputPath: dirname(this.options.outputPath),
|
||||||
baseHref: this.options.baseHref,
|
baseHref: this.options.baseHref,
|
||||||
|
|||||||
@ -59,13 +59,7 @@ export interface FileInfo {
|
|||||||
* bundles for differential serving.
|
* bundles for differential serving.
|
||||||
*/
|
*/
|
||||||
export function augmentIndexHtml(params: AugmentIndexHtmlOptions): string {
|
export function augmentIndexHtml(params: AugmentIndexHtmlOptions): string {
|
||||||
const {
|
const { loadOutputFile, files, moduleFiles = [], entrypoints } = params;
|
||||||
loadOutputFile,
|
|
||||||
files,
|
|
||||||
noModuleFiles = [],
|
|
||||||
moduleFiles = [],
|
|
||||||
entrypoints,
|
|
||||||
} = params;
|
|
||||||
|
|
||||||
let { crossOrigin = 'none' } = params;
|
let { crossOrigin = 'none' } = params;
|
||||||
if (params.sri && crossOrigin === 'none') {
|
if (params.sri && crossOrigin === 'none') {
|
||||||
@ -76,7 +70,7 @@ export function augmentIndexHtml(params: AugmentIndexHtmlOptions): string {
|
|||||||
const scripts = new Set<string>();
|
const scripts = new Set<string>();
|
||||||
|
|
||||||
// Sort files in the order we want to insert them by entrypoint and dedupes duplicates
|
// Sort files in the order we want to insert them by entrypoint and dedupes duplicates
|
||||||
const mergedFiles = [...moduleFiles, ...noModuleFiles, ...files];
|
const mergedFiles = [...moduleFiles, ...files];
|
||||||
for (const entrypoint of entrypoints) {
|
for (const entrypoint of entrypoints) {
|
||||||
for (const { extension, file, name } of mergedFiles) {
|
for (const { extension, file, name } of mergedFiles) {
|
||||||
if (name !== entrypoint) {
|
if (name !== entrypoint) {
|
||||||
@ -160,15 +154,9 @@ export function augmentIndexHtml(params: AugmentIndexHtmlOptions): string {
|
|||||||
// in some cases for differential loading file with the same name is avialable in both
|
// in some cases for differential loading file with the same name is avialable in both
|
||||||
// nomodule and module such as scripts.js
|
// nomodule and module such as scripts.js
|
||||||
// we shall not add these attributes if that's the case
|
// we shall not add these attributes if that's the case
|
||||||
const isNoModuleType = noModuleFiles.some(scriptPredictor);
|
|
||||||
const isModuleType = moduleFiles.some(scriptPredictor);
|
const isModuleType = moduleFiles.some(scriptPredictor);
|
||||||
|
|
||||||
if (isNoModuleType && !isModuleType) {
|
if (isModuleType) {
|
||||||
attrs.push({ name: 'nomodule', value: null });
|
|
||||||
if (!script.startsWith('polyfills-nomodule-es5')) {
|
|
||||||
attrs.push({ name: 'defer', value: null });
|
|
||||||
}
|
|
||||||
} else if (isModuleType) {
|
|
||||||
attrs.push({ name: 'type', value: 'module' });
|
attrs.push({ name: 'type', value: 'module' });
|
||||||
} else {
|
} else {
|
||||||
attrs.push({ name: 'defer', value: null });
|
attrs.push({ name: 'defer', value: null });
|
||||||
@ -293,7 +281,6 @@ export async function writeIndexHtml({
|
|||||||
outputPath,
|
outputPath,
|
||||||
indexPath,
|
indexPath,
|
||||||
files = [],
|
files = [],
|
||||||
noModuleFiles = [],
|
|
||||||
moduleFiles = [],
|
moduleFiles = [],
|
||||||
baseHref,
|
baseHref,
|
||||||
deployUrl,
|
deployUrl,
|
||||||
@ -314,7 +301,6 @@ export async function writeIndexHtml({
|
|||||||
sri,
|
sri,
|
||||||
entrypoints: generateEntryPoints({ scripts, styles }),
|
entrypoints: generateEntryPoints({ scripts, styles }),
|
||||||
files: filterAndMapBuildFiles(files, ['.js', '.css']),
|
files: filterAndMapBuildFiles(files, ['.js', '.css']),
|
||||||
noModuleFiles: filterAndMapBuildFiles(noModuleFiles, '.js'),
|
|
||||||
moduleFiles: filterAndMapBuildFiles(moduleFiles, '.js'),
|
moduleFiles: filterAndMapBuildFiles(moduleFiles, '.js'),
|
||||||
loadOutputFile: (filePath) =>
|
loadOutputFile: (filePath) =>
|
||||||
readFileSync(join(dirname(outputPath), filePath)).toString(),
|
readFileSync(join(dirname(outputPath), filePath)).toString(),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user