merge: webpack updates (#9870)

* refactor(webpack): use global require for checking hmr chunks

* wip: watchstate plugin adjustments

* feat(webpack): emit hrm boot status

* chore: bump deps

* fix(hmr): emit boot log at boot instead of the 1st livesync

* chore(release): @nativescript/webpack 5.0.8-alpha.0

* refactor(webpack): use real modules and deprecate virtual modules

* feat(webpack): allow disabling nativescriptLibPath warning with a boolean

* fix(webpack): remove copy rules that don't match any files to avoid false watch triggers

* feat(webpack): add --env.stats to disable printing stats
primarily used internally by preview-cli

* chore(release): @nativescript/webpack 5.0.8-alpha.2

* fix: revert copy rule glob filter

* chore(release): @nativescript/webpack 5.0.8-alpha.3
This commit is contained in:
Igor Randjelovic
2022-07-26 01:05:55 +02:00
committed by GitHub
15 changed files with 133 additions and 128 deletions

View File

@ -302,16 +302,6 @@ exports[`javascript configuration for android 1`] = `
),
/* config.plugin('WatchStatePlugin') */
new WatchStatePlugin(),
/* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_javascript__') */
new ContextExclusionPlugin(
/__@nativescript_webpack_virtual_entry_javascript__.js$/
),
/* config.plugin('VirtualModulesPlugin') */
new VirtualModulesPlugin(
{
'__jest__/src/__@nativescript_webpack_virtual_entry_javascript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END'
}
),
/* config.plugin('ContextExclusionPlugin|exclude_files') */
new ContextExclusionPlugin(
/\\\\b_.+\\\\./
@ -320,7 +310,7 @@ exports[`javascript configuration for android 1`] = `
entry: {
bundle: [
'@nativescript/core/globals/index',
'__jest__/src/__@nativescript_webpack_virtual_entry_javascript__',
'__jest__/node_modules/@nativescript/webpack/dist/stubs/virtual-entry-javascript',
'@nativescript/core/bundle-entry-points',
'__jest__/src/app.js',
'@nativescript/core/ui/frame',
@ -632,16 +622,6 @@ exports[`javascript configuration for ios 1`] = `
),
/* config.plugin('WatchStatePlugin') */
new WatchStatePlugin(),
/* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_javascript__') */
new ContextExclusionPlugin(
/__@nativescript_webpack_virtual_entry_javascript__.js$/
),
/* config.plugin('VirtualModulesPlugin') */
new VirtualModulesPlugin(
{
'__jest__/src/__@nativescript_webpack_virtual_entry_javascript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END'
}
),
/* config.plugin('ContextExclusionPlugin|exclude_files') */
new ContextExclusionPlugin(
/\\\\b_.+\\\\./
@ -650,7 +630,7 @@ exports[`javascript configuration for ios 1`] = `
entry: {
bundle: [
'@nativescript/core/globals/index',
'__jest__/src/__@nativescript_webpack_virtual_entry_javascript__',
'__jest__/node_modules/@nativescript/webpack/dist/stubs/virtual-entry-javascript',
'@nativescript/core/bundle-entry-points',
'__jest__/src/app.js'
],

View File

@ -302,16 +302,6 @@ exports[`typescript configuration for android 1`] = `
),
/* config.plugin('WatchStatePlugin') */
new WatchStatePlugin(),
/* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_typescript__') */
new ContextExclusionPlugin(
/__@nativescript_webpack_virtual_entry_typescript__.js$/
),
/* config.plugin('VirtualModulesPlugin') */
new VirtualModulesPlugin(
{
'__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /\\\\\\\\.(xml|js|(?<!\\\\\\\\.d\\\\\\\\.)ts|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END'
}
),
/* config.plugin('ContextExclusionPlugin|exclude_files') */
new ContextExclusionPlugin(
/\\\\b_.+\\\\./
@ -320,7 +310,7 @@ exports[`typescript configuration for android 1`] = `
entry: {
bundle: [
'@nativescript/core/globals/index',
'__jest__/src/__@nativescript_webpack_virtual_entry_typescript__',
'__jest__/node_modules/@nativescript/webpack/dist/stubs/virtual-entry-typescript.js',
'@nativescript/core/bundle-entry-points',
'__jest__/src/app.js',
'@nativescript/core/ui/frame',
@ -632,16 +622,6 @@ exports[`typescript configuration for ios 1`] = `
),
/* config.plugin('WatchStatePlugin') */
new WatchStatePlugin(),
/* config.plugin('ContextExclusionPlugin|__@nativescript_webpack_virtual_entry_typescript__') */
new ContextExclusionPlugin(
/__@nativescript_webpack_virtual_entry_typescript__.js$/
),
/* config.plugin('VirtualModulesPlugin') */
new VirtualModulesPlugin(
{
'__jest__/src/__@nativescript_webpack_virtual_entry_typescript__': '// VIRTUAL ENTRY START\\\\nrequire(\\\\'@nativescript/core/bundle-entry-points\\\\')\\\\nconst context = require.context(\\"~/\\", /* deep: */ true, /* filter: */ /\\\\\\\\.(xml|js|(?<!\\\\\\\\.d\\\\\\\\.)ts|s?css)$/);\\\\nglobal.registerWebpackModules(context);\\\\n// VIRTUAL ENTRY END'
}
),
/* config.plugin('ContextExclusionPlugin|exclude_files') */
new ContextExclusionPlugin(
/\\\\b_.+\\\\./
@ -650,7 +630,7 @@ exports[`typescript configuration for ios 1`] = `
entry: {
bundle: [
'@nativescript/core/globals/index',
'__jest__/src/__@nativescript_webpack_virtual_entry_typescript__',
'__jest__/node_modules/@nativescript/webpack/dist/stubs/virtual-entry-typescript.js',
'@nativescript/core/bundle-entry-points',
'__jest__/src/app.js'
],

View File

@ -1,4 +1,6 @@
import Config from 'webpack-chain';
import path from 'path';
import fs from 'fs';
import typescript from '../../src/configuration/typescript';
import { init } from '../../src';
@ -15,29 +17,30 @@ describe('typescript configuration', () => {
});
}
it('filter typescript declaration files', () => {
it('filters typescript declaration files', () => {
init({
ios: true,
});
const tsConfig = typescript(new Config());
// const tsConfig = typescript(new Config());
let regex: RegExp;
// Get the filterRE from the typescript configuration
tsConfig.plugin('VirtualModulesPlugin').tap((args) => {
const options = args[0];
const virtualConfig: string = options[Object.keys(options)[0]];
const filterLine = virtualConfig
.split('\n')
.find((v) => v.includes('filter'));
const matches = filterLine.match(/\/(?<filter>\S+)\//);
const virtualEntryPath = path.join(
__dirname,
'../../src/stubs/virtual-entry-typescript.js'
);
const virtualEntry = fs.readFileSync(virtualEntryPath);
if (matches) {
regex = new RegExp(matches.groups.filter);
}
const filterLine = virtualEntry
.toString()
.split('\n')
.find((v) => v.includes('filter'));
return args;
});
const matches = filterLine.match(/\/(?<filter>\S+)\//);
if (matches) {
regex = new RegExp(matches.groups.filter);
}
expect(regex).toBeDefined();

View File

@ -1,6 +1,6 @@
{
"name": "@nativescript/webpack",
"version": "5.0.7",
"version": "5.0.8-alpha.3",
"private": false,
"main": "dist/index.js",
"files": [
@ -29,17 +29,17 @@
"css": "^3.0.0",
"css-loader": "^6.0.0",
"dotenv-webpack": "^7.0.0",
"fork-ts-checker-webpack-plugin": "^6.0.0",
"loader-utils": "^2.0.0",
"fork-ts-checker-webpack-plugin": "^7.0.0",
"loader-utils": "^2.0.0 || ^3.0.0",
"lodash.get": "^4.0.0",
"micromatch": "^4.0.0",
"postcss": "^8.0.0",
"postcss-import": "^14.0.0",
"postcss-loader": "^6.0.0",
"postcss-loader": "^7.0.0",
"raw-loader": "^4.0.0",
"react-refresh": "~0.11.0",
"sass": "^1.0.0",
"sass-loader": "^12.0.0",
"sass-loader": "^13.0.0",
"sax": "^1.0.0",
"source-map": "^0.7.0",
"terser-webpack-plugin": "^5.0.0",
@ -56,17 +56,17 @@
"devDependencies": {
"@angular-devkit/build-angular": "^13.1.2",
"@types/css": "0.0.33",
"@types/jest": "27.0.1",
"@types/jest": "27.5.1",
"@types/loader-utils": "2.0.3",
"@types/lodash.get": "4.4.6",
"@types/lodash.get": "4.4.7",
"@types/micromatch": "4.0.2",
"@types/sax": "1.2.3",
"@types/sax": "1.2.4",
"@types/terser-webpack-plugin": "5.2.0",
"@types/webpack-virtual-modules": "0.1.1",
"jest": "27.1.1",
"jest-matcher-utils": "27.1.1",
"nativescript-vue-template-compiler": "2.9.0",
"ts-jest": "27.0.5",
"jest": "28.1.0",
"jest-matcher-utils": "28.1.0",
"nativescript-vue-template-compiler": "2.9.2",
"ts-jest": "28.0.3",
"typescript": "4.7.3"
},
"peerDependencies": {

View File

@ -56,6 +56,7 @@ program
env['env'] = options.env;
}
env['stats'] ??= true;
env['watch'] ??= options.watch;
// if --env.config is passed, we'll set an environment
@ -108,13 +109,15 @@ program
// Set the process exit code depending on errors
process.exitCode = stats.hasErrors() ? 1 : 0;
console.log(
stats.toString({
chunks: false,
colors: true,
errorDetails: env.verbose,
})
);
if (env.stats) {
console.log(
stats.toString({
chunks: false,
colors: true,
errorDetails: env.verbose,
})
);
}
// if webpack profile is enabled we write the stats to a JSON file
if (configuration.profile || env.profile) {
@ -141,7 +144,7 @@ program
};
if (options.watch) {
console.log('webpack is watching the files...');
env.stats && console.log('webpack is watching the files...');
compiler.watch(
configuration.watchOptions ?? {},
webpackCompilationCallback

View File

@ -1,26 +1,18 @@
import Config from 'webpack-chain';
import { getEntryPath, getEntryDirPath } from '../helpers/platform';
import { addVirtualEntry } from '../helpers/virtualModules';
import { chainedSetAddAfter } from '../helpers/chain';
import { env as _env, IWebpackEnv } from '../index';
import { ContextExclusionPlugin } from 'webpack';
import base from './base';
import path from 'path';
export default function (config: Config, env: IWebpackEnv = _env): Config {
base(config, env);
const entryPath = getEntryPath();
const filterRE = '/.(xml|js|s?css)$/';
const virtualEntryPath = addVirtualEntry(
config,
'javascript',
`
// VIRTUAL ENTRY START
require('@nativescript/core/bundle-entry-points')
const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE});
global.registerWebpackModules(context);
// VIRTUAL ENTRY END
`
const virtualEntryPath = path.resolve(
__dirname,
'../stubs/virtual-entry-javascript'
);
// exclude files starting with _ from require.context

View File

@ -1,26 +1,18 @@
import Config from 'webpack-chain';
import { getEntryDirPath, getEntryPath } from '../helpers/platform';
import { addVirtualEntry } from '../helpers/virtualModules';
import { chainedSetAddAfter } from '../helpers/chain';
import { env as _env, IWebpackEnv } from '../index';
import { ContextExclusionPlugin } from 'webpack';
import base from './base';
import path from 'path';
export default function (config: Config, env: IWebpackEnv = _env): Config {
base(config, env);
const entryPath = getEntryPath();
const filterRE = '/\\.(xml|js|(?<!\\.d\\.)ts|s?css)$/';
const virtualEntryPath = addVirtualEntry(
config,
'typescript',
`
// VIRTUAL ENTRY START
require('@nativescript/core/bundle-entry-points')
const context = require.context("~/", /* deep: */ true, /* filter: */ ${filterRE});
global.registerWebpackModules(context);
// VIRTUAL ENTRY END
`
const virtualEntryPath = path.resolve(
__dirname,
'../stubs/virtual-entry-typescript.js'
);
// exclude files starting with _ from require.context

View File

@ -3,16 +3,22 @@ import { env } from '../index';
function getCLILib() {
if (!env.nativescriptLibPath) {
warnOnce(
'getCLILib',
`
Cannot find NativeScript CLI path. Make sure --env.nativescriptLibPath is passed
`
);
if (typeof env.nativescriptLibPath !== 'boolean') {
warnOnce(
'getCLILib',
`
Cannot find NativeScript CLI path. Make sure --env.nativescriptLibPath is passed
`
);
}
return false;
}
return require(env.nativescriptLibPath);
if (typeof env.nativescriptLibPath === 'boolean') {
return false;
}
return require(env.nativescriptLibPath as string);
}
/**

View File

@ -1,6 +1,7 @@
import CopyWebpackPlugin from 'copy-webpack-plugin';
import { basename, relative, resolve } from 'path';
import Config from 'webpack-chain';
import { sync as globbySync } from 'globby';
import { getProjectRootPath } from './project';
import { getEntryDirPath } from './platform';
@ -70,6 +71,17 @@ export function applyCopyRules(config: Config) {
config.plugin('CopyWebpackPlugin').use(CopyWebpackPlugin, [
{
patterns: Array.from(copyRules)
// reverted: removes valid rules occasionally (ie fonts)
// todo: re-visit in future...
// .filter((glob) => {
// if (process.env.NODE_ENV === 'test') {
// return true;
// }
// // remove rules that do not match any paths
// // prevents webpack watch mode from firing
// // due to "removed" paths.
// return globbySync(glob).length > 0;
// })
.map((glob) => ({
from: glob,
context: entryDir,

View File

@ -8,6 +8,9 @@ import { getEntryDirPath } from './platform';
import dedent from 'ts-dedent';
import { getProjectFilePath } from './project';
/**
* @deprecated Virtual entries are not recommended by the webpack team, use real files instead. For example, resolve a path in node_modules if necessary.
*/
export function addVirtualEntry(
config: Config,
name: string,
@ -20,6 +23,9 @@ export function addVirtualEntry(
);
}
/**
* @deprecated Virtual modules are not recommended by the webpack team, use real files instead. For example, resolve a path in node_modules if necessary.
*/
export function addVirtualModule(
config: Config,
name: string,

View File

@ -28,7 +28,7 @@ export interface IWebpackEnv {
appResourcesPath?: string;
appComponents?: string[];
nativescriptLibPath?: string;
nativescriptLibPath?: string | boolean;
android?: boolean;
ios?: boolean;
@ -46,6 +46,9 @@ export interface IWebpackEnv {
// enable webpack profiling
profile?: boolean;
// print webpack stats (default: true)
stats?: boolean;
// misc
replace?: string[] | string;
watchNodeModules?: boolean;

View File

@ -5,6 +5,7 @@
if (module.hot) {
let hash = __webpack_require__.h();
let hmrBootEmittedSymbol = Symbol.for('HMRBootEmitted');
const logVerbose = (title: string, ...info: any) => {
if (__NS_ENV_VERBOSE__) {
@ -19,7 +20,7 @@ if (module.hot) {
const setStatus = (
hash: string,
status: 'success' | 'failure',
status: 'success' | 'failure' | 'boot',
message?: string,
...info: any
): boolean => {
@ -93,7 +94,7 @@ if (module.hot) {
const requireExists = (path) => {
try {
__non_webpack_require__(path);
global['require'](path);
return true;
} catch (err) {
return false;
@ -112,10 +113,18 @@ if (module.hot) {
logVerbose('LiveSync');
if (!hasUpdate()) {
return;
return false;
}
await checkAndApply();
originalOnLiveSync();
if (!(await checkAndApply())) {
return false;
}
await originalOnLiveSync();
};
if (!global[hmrBootEmittedSymbol]) {
global[hmrBootEmittedSymbol] = true;
setStatus(hash, 'boot', 'HMR Enabled - waiting for changes...');
}
}

View File

@ -22,7 +22,7 @@ export class WatchStatePlugin {
callback();
if (isWatchMode) {
console.log(messages.changeDetected);
env.stats && console.log(messages.changeDetected);
if (env.verbose) {
if (compiler.modifiedFiles) {
@ -44,9 +44,10 @@ export class WatchStatePlugin {
compiler.hooks.afterEmit.tapAsync(id, function (compilation, callback) {
callback();
console.log(
isWatchMode ? messages.startWatching : messages.compilationComplete
);
env.stats &&
console.log(
isWatchMode ? messages.startWatching : messages.compilationComplete
);
// Do not notify the CLI if the compilation failed
const stats = compilation.getStats();
@ -55,16 +56,24 @@ export class WatchStatePlugin {
}
// logic taken from CleanWebpackPlugin
const assets =
stats.toJson(
{
assets: true,
},
true
).assets || [];
const assetList = assets.map((asset) => asset.name);
// const assets =
// stats.toJson(
// {
// assets: true,
// },
// true
// ).assets || [];
// const assetList = assets.map((asset) => asset.name);
// const emittedAssets = Array.from(compilation.emittedAssets);
const assetList = Object.keys(compilation.assets);
const emittedAssets = Array.from(compilation.emittedAssets);
if (!prevAssets.length && emittedAssets.length < assetList.length) {
emittedAssets.push(...assetList);
}
const staleAssets = prevAssets.filter((asset) => {
return assetList.includes(asset) === false;
});

View File

@ -0,0 +1,5 @@
// VIRTUAL ENTRY START
require('@nativescript/core/bundle-entry-points')
const context = require.context("~/", /* deep: */ true, /* filter: */ /.(xml|js|s?css)$/);
global.registerWebpackModules(context);
// VIRTUAL ENTRY END

View File

@ -0,0 +1,5 @@
// VIRTUAL ENTRY START
require('@nativescript/core/bundle-entry-points')
const context = require.context("~/", /* deep: */ true, /* filter: */ /\.(xml|js|(?<!\.d\.)ts|s?css)$/);
global.registerWebpackModules(context);
// VIRTUAL ENTRY END