如何防止 karma-webpack 创建供应商代码的源映射?
How to prevent karma-webpack from creating source maps of vendor code?
我在 Karma 测试 运行 中遇到了非常慢的 "boot" 次,在分析 运行 之后,我意识到最大的减速是由源映射的创建引起的.
更具体地说,假设我使用 karma-webpack
和 webpack 作为预处理器,每次测试文件被 karma 加载时,它都会被提供给 webpack,后者会为其生成源映射。
鉴于我不是 splitting/chunking 我的应用程序和供应商代码,每个测试文件都获得相同的供应商源映射(内联)。
我认为我可以通过简单地防止 node_modules/
文件发生源映射来解决这个问题,但我意识到你只能根据最终资产文件而不是输入 source/module 个文件。
所以我发现 this 插件可以自动将我的应用程序和供应商代码分成单独的块(而不是必须手动列出每个供应商模块)。
然而当 运行ning Karma 时我开始遇到这个错误:
ReferenceError: Can't find variable: webpackJsonp
我很确定这是由于 Karma 没有意识到供应商和应用程序代码被拆分成单独的块这一事实造成的,因此只包括使用 [=13= 配置的代码] 选项(即测试文件本身而不是供应商文件)。
似乎 files
配置选项在每个测试文件被预处理之前被解析和处理,这意味着我认为不可能在 files
中指定供应商块选项,因为 Karma 在它试图寻找它时并不知道它(太早)。
我能看到的唯一解决方案是:
- 更改 Karma 的实现方式,使其可以处理供应商和应用程序块文件的分离。
- 不使用
karma-webpack
和预处理,而是在测试模式下构建应用程序,然后 运行 测试构建目录的 Karma(以便供应商块足够早地存在)。
是否有我遗漏的解决方案?
我觉得很奇怪,这似乎不是一个普遍的问题。
编辑 1
我找到了 this,但是那里的人建议在 webpack 配置中使用多个入口点(即一个用于应用程序,一个用于供应商)。我会尝试看看这是否适用于 Karma,但它仍然有一个很大的缺点(在我看来),你必须手动跟踪你放入 vendor
数组的内容。 IE。每次安装包时都必须将其添加到数组中,反之亦然。
编辑 2
在我配置源映射 webpack 插件以排除供应商文件之前,使用多个入口点(在 webpack 配置中)甚至不起作用(而使用 webpack-split-by-path
插件)。
我将尝试实施 "build first and then test" 方法。
如果其他人遇到这个问题,我使用了 "build then rest" 方法,即我放弃了 karma-webpack
和 Karma 预处理,转而使用单独的构建和测试命令(得到 运行一个接一个)。
这是我的特定于测试的 webpack 配置(例如 webpack.config.babel.test.js):
import webpack from 'webpack';
import { join, resolve, parse } from 'path';
import SplitByPathPlugin from 'webpack-split-by-path';
import file from 'file';
const plugins = [
new SplitByPathPlugin([
{
name: 'vendor',
path: resolve(__dirname, 'node_modules')
}
]),
new webpack.SourceMapDevToolPlugin({
test: /\.jsx?$/,
exclude: [/vendor/]
})
];
const entryPoints = {};
const testFileRegex = new RegExp('\.test\.jsx?$');
const pathPrefixRegex = new RegExp('^src/js/?');
file.walkSync('src/js/', (dirPath, dirs, files) => {
for (const file of files) {
if (file.match(testFileRegex)) {
const parsedPath = parse(file);
const entryKey = join(
dirPath.replace(pathPrefixRegex, ''),
parsedPath.name
);
entryPoints[entryKey] = './' + join(dirPath, parsedPath.name);
}
}
});
const config = {
entry: entryPoints,
output: {
filename: '/[name]-[chunkhash].js',
chunkFilename: '/[name]-[chunkhash].js',
path: resolve(__dirname, 'dist-test'),
pathinfo: true
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader!eslint-loader',
exclude: [/node_modules/],
},
{
test: /\.json$/, loader: 'json'
}
],
},
bail: true,
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
},
plugins: plugins,
stats: {
assets: false,
cached: false,
children: false,
chunks: false,
chunkModules: false,
chunkOrigins: false,
hash: false,
modules: false,
publicPath: false,
reasons: false,
source: false,
timings: false,
version: false,
warnings: false
},
node: {
child_process: 'empty',
fs: 'empty'
},
externals: {
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': 'window'
}
};
export default config;
关键部分是它为每个测试文件创建一个入口点,并使用 webpack-split-by-path
插件在生成块时自动将应用程序与供应商代码分开。
这是我使用的 karma 配置:
process.env.BABEL_ENV = 'test';
function karmaConfig(config) {
config.set({
basePath: '',
frameworks: ['mocha'],
files: [
{
pattern: 'dist-test/vendor-*.js',
watched: false
},
'dist-test/**/*.test-*js?(x)'
],
exclude: [],
reporters: ['progress'],
port: 9876,
colors: true,
browsers: ['Firefox', 'Chrome'],
singleRun: true,
logLevel: config.LOG_ERROR
})
}
export default karmaConfig;
关键部分是供应商文件在files
配置选项中列在第一位,并设置为不被监视,然后是测试文件。这确保了每个测试用例的供应商代码总是 loaded/inserted 第一。
我的问题是问是否有其他方法,但这种方法效果很好。性能好多了。
编辑 1
这种方法的唯一缺点(我一开始没有意识到)是你不能像使用 karma-webpack
和预处理(通过 webpack)那样真正实现测试观察,因为构建和测试步骤的解耦。
编辑 2
这种方法遇到了每次更改应用程序代码时重新编译供应商代码的问题(即使您没有add/remove任何供应商库) .这多余地减慢了速度。
你想要解决这个问题并能够再次开始测试观看的方法是:
- 运行 监视模式下的 Webpack,当您的应用程序代码发生变化时构建到您的
dist-test/
目录中。
- 运行 观察模式下的 Karma 指向
dist-test/
目录中正在更新的所有测试文件。
这个解决方案是完美的,除了一个缺点,即您不能在一个 npm/yarn 命令中 运行 两者兼顾。
注意:您的 Webpack 测试构建的输出文件名不应包含任何哈希值(即文件名在其内容更改之间应保持一致)。这样当您更改测试文件时,您不会 运行 旧测试代码和新测试代码(因为 Webpack 不会删除旧文件)。.
我在 Karma 测试 运行 中遇到了非常慢的 "boot" 次,在分析 运行 之后,我意识到最大的减速是由源映射的创建引起的.
更具体地说,假设我使用 karma-webpack
和 webpack 作为预处理器,每次测试文件被 karma 加载时,它都会被提供给 webpack,后者会为其生成源映射。
鉴于我不是 splitting/chunking 我的应用程序和供应商代码,每个测试文件都获得相同的供应商源映射(内联)。
我认为我可以通过简单地防止 node_modules/
文件发生源映射来解决这个问题,但我意识到你只能根据最终资产文件而不是输入 source/module 个文件。
所以我发现 this 插件可以自动将我的应用程序和供应商代码分成单独的块(而不是必须手动列出每个供应商模块)。
然而当 运行ning Karma 时我开始遇到这个错误:
ReferenceError: Can't find variable: webpackJsonp
我很确定这是由于 Karma 没有意识到供应商和应用程序代码被拆分成单独的块这一事实造成的,因此只包括使用 [=13= 配置的代码] 选项(即测试文件本身而不是供应商文件)。
似乎 files
配置选项在每个测试文件被预处理之前被解析和处理,这意味着我认为不可能在 files
中指定供应商块选项,因为 Karma 在它试图寻找它时并不知道它(太早)。
我能看到的唯一解决方案是:
- 更改 Karma 的实现方式,使其可以处理供应商和应用程序块文件的分离。
- 不使用
karma-webpack
和预处理,而是在测试模式下构建应用程序,然后 运行 测试构建目录的 Karma(以便供应商块足够早地存在)。
是否有我遗漏的解决方案?
我觉得很奇怪,这似乎不是一个普遍的问题。
编辑 1
我找到了 this,但是那里的人建议在 webpack 配置中使用多个入口点(即一个用于应用程序,一个用于供应商)。我会尝试看看这是否适用于 Karma,但它仍然有一个很大的缺点(在我看来),你必须手动跟踪你放入 vendor
数组的内容。 IE。每次安装包时都必须将其添加到数组中,反之亦然。
编辑 2
在我配置源映射 webpack 插件以排除供应商文件之前,使用多个入口点(在 webpack 配置中)甚至不起作用(而使用 webpack-split-by-path
插件)。
我将尝试实施 "build first and then test" 方法。
如果其他人遇到这个问题,我使用了 "build then rest" 方法,即我放弃了 karma-webpack
和 Karma 预处理,转而使用单独的构建和测试命令(得到 运行一个接一个)。
这是我的特定于测试的 webpack 配置(例如 webpack.config.babel.test.js):
import webpack from 'webpack';
import { join, resolve, parse } from 'path';
import SplitByPathPlugin from 'webpack-split-by-path';
import file from 'file';
const plugins = [
new SplitByPathPlugin([
{
name: 'vendor',
path: resolve(__dirname, 'node_modules')
}
]),
new webpack.SourceMapDevToolPlugin({
test: /\.jsx?$/,
exclude: [/vendor/]
})
];
const entryPoints = {};
const testFileRegex = new RegExp('\.test\.jsx?$');
const pathPrefixRegex = new RegExp('^src/js/?');
file.walkSync('src/js/', (dirPath, dirs, files) => {
for (const file of files) {
if (file.match(testFileRegex)) {
const parsedPath = parse(file);
const entryKey = join(
dirPath.replace(pathPrefixRegex, ''),
parsedPath.name
);
entryPoints[entryKey] = './' + join(dirPath, parsedPath.name);
}
}
});
const config = {
entry: entryPoints,
output: {
filename: '/[name]-[chunkhash].js',
chunkFilename: '/[name]-[chunkhash].js',
path: resolve(__dirname, 'dist-test'),
pathinfo: true
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader!eslint-loader',
exclude: [/node_modules/],
},
{
test: /\.json$/, loader: 'json'
}
],
},
bail: true,
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
},
plugins: plugins,
stats: {
assets: false,
cached: false,
children: false,
chunks: false,
chunkModules: false,
chunkOrigins: false,
hash: false,
modules: false,
publicPath: false,
reasons: false,
source: false,
timings: false,
version: false,
warnings: false
},
node: {
child_process: 'empty',
fs: 'empty'
},
externals: {
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': 'window'
}
};
export default config;
关键部分是它为每个测试文件创建一个入口点,并使用 webpack-split-by-path
插件在生成块时自动将应用程序与供应商代码分开。
这是我使用的 karma 配置:
process.env.BABEL_ENV = 'test';
function karmaConfig(config) {
config.set({
basePath: '',
frameworks: ['mocha'],
files: [
{
pattern: 'dist-test/vendor-*.js',
watched: false
},
'dist-test/**/*.test-*js?(x)'
],
exclude: [],
reporters: ['progress'],
port: 9876,
colors: true,
browsers: ['Firefox', 'Chrome'],
singleRun: true,
logLevel: config.LOG_ERROR
})
}
export default karmaConfig;
关键部分是供应商文件在files
配置选项中列在第一位,并设置为不被监视,然后是测试文件。这确保了每个测试用例的供应商代码总是 loaded/inserted 第一。
我的问题是问是否有其他方法,但这种方法效果很好。性能好多了。
编辑 1
这种方法的唯一缺点(我一开始没有意识到)是你不能像使用 karma-webpack
和预处理(通过 webpack)那样真正实现测试观察,因为构建和测试步骤的解耦。
编辑 2
这种方法遇到了每次更改应用程序代码时重新编译供应商代码的问题(即使您没有add/remove任何供应商库) .这多余地减慢了速度。
你想要解决这个问题并能够再次开始测试观看的方法是:
- 运行 监视模式下的 Webpack,当您的应用程序代码发生变化时构建到您的
dist-test/
目录中。 - 运行 观察模式下的 Karma 指向
dist-test/
目录中正在更新的所有测试文件。
这个解决方案是完美的,除了一个缺点,即您不能在一个 npm/yarn 命令中 运行 两者兼顾。
注意:您的 Webpack 测试构建的输出文件名不应包含任何哈希值(即文件名在其内容更改之间应保持一致)。这样当您更改测试文件时,您不会 运行 旧测试代码和新测试代码(因为 Webpack 不会删除旧文件)。.