Webpack 缩小分发文件问题
Webpack minified distribution file issue
首先我得说我是一个 webpack 新手,我已经使用这个很棒的工具大约 2 周了,除了这个我已经设法实现了我需要的一切。
事情是这样的:在我的公司,我们正试图将一组通用的输入、组件和通用 css 抽象到托管在单独存储库中的模块,以便它可以作为我们其他模块中的供应商, 它叫做 Mandioca。我们所有的应用程序都是使用 Angularjs 框架开发的,因此它是一个 angular 模块。
我将所有内容捆绑在一个包含所有 .js
文件的缩小文件中,并将其输出到名为 dist
的文件夹中。没什么大不了的。
当我尝试在任何其他模块中导入 mandioca 时会出现此问题。我收到此异常:TypeError: Failed to construct 'WebSocket': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
我认为这是缩小文件中的问题,因为当我停止在模块的依赖项上导入 Mandioca 时,错误消失了:
// Exception :(
angular.module('app', [
'Mandioca',
// (...other dependencies)
]);
// Everything OK
angular.module('app', [
// (...other dependencies)
]);
我深入研究了 webpack 配置文档和 angular + webpack cookbook,发现了一些有趣的东西,但遗憾的是没有解决我的问题:
指定 externals
:
externals: {
angular: 'angular',
}
指定 output
libraryTarget 选项:
config.output = {
path: path.join(__dirname, distFolder),
filename: (isBuild ? minJs : '[name].bundle.js'),
libraryTarget: 'umd' // <--- here's the tweak
};
其他一些注意事项:
- Mandioca 模块正常运行开发任务,使用缩小文件进行开发也没有崩溃。
- 所有其他模块正常运行开发任务
- 我正在使用 webpack-dev-server 来完成这些任务。
Mandioca 的 Webpack 文件:
// webpack stuff
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import WebpackNotifierPlugin from 'webpack-notifier';
// import CopyWebpackPlugin from 'copy-webpack-plugin';
// postcss
import rucksack from 'rucksack-css';
import cssnano from 'cssnano';
import nested from 'postcss-nested';
import mixins from 'postcss-mixins';
import simpleVars from 'postcss-simple-vars';
import cssnext from 'postcss-cssnext';
import postcssImport from 'postcss-import';
import vendors from './vendors.json';
import path from 'path';
export default function makeWebpackConfig(options) {
const vendorsDir = path.join(__dirname, 'node_modules');
const excludeVendors = /node_modules/;
const distFolder = 'dist';
const minJs = 'mandioca.min.js';
const minCss = 'mandioca.min.css';
const devEntry = './app/app.dev.js';
const distEntry = './app/app.dist.js';
const isTest = !!options.TEST;
const isBuild = !!options.BUILD;
const isDev = !isBuild && !!options.DEV;
const isDevProd = isBuild && !!options.DEV;
const getCssLoader = (build) => {
let baseStr = 'css?sourceMap!postcss';
return build ? ExtractTextPlugin.extract('style', baseStr) : 'style!' + baseStr;
};
const esLintPreLoader = {
test: /\.js$/,
loader: 'eslint',
exclude: excludeVendors
};
const jsLoader = {
test: /\.js$/,
loaders: ['ng-annotate', 'babel'],
exclude: excludeVendors
};
const cssLoader = {
test: /\.css$/,
loader: getCssLoader(isBuild),
exclude: excludeVendors
};
const vendorsCssLoader = {
test: /\.css$/,
loader: 'style!css?sourceMap',
include: excludeVendors
};
const filesLoader = {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
loader: 'file',
exclude: excludeVendors
};
const htmlLoader = {
test: /\.html$/,
loaders: ['ngtemplate', 'html'],
exclude: excludeVendors
};
const config = {
resolve: {
alias: {}
},
plugins: [],
entry: {
app: ((isBuild && !isDevProd) ? distEntry : devEntry),
vendor: []
},
module: {},
externals: {
angular: 'angular',
}
};
config.output = {
path: path.join(__dirname, distFolder),
filename: (isBuild ? minJs : '[name].bundle.js'),
libraryTarget: 'umd'
};
if (!isBuild && (isDev || isDevProd)) {
config.module.noParse = [];
vendors.forEach((vendor) => {
let vendorPath = path.resolve(vendorsDir, vendor);
// config.module.noParse.push(vendorPath);
config.entry.vendor.push(vendorPath);
config.resolve.alias[vendor.split(path.sep)[0]] = vendorPath;
});
}
if (!isTest) {
// Reference: https://github.com/ampedandwired/html-webpack-plugin
// Render index.html
config.plugins.push(
new HtmlWebpackPlugin({
template: './index.html',
inject: true,
production: isBuild,
}),
new webpack.ProvidePlugin({
moment: 'moment',
R: 'ramda',
CPF: 'cpf_cnpj'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: (isBuild && !isDevProd) ? minJs : '[name].bundle.js',
}),
// Reference: https://github.com/Turbo87/webpack-notifier
// Pops a notification on error
new WebpackNotifierPlugin(),
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }})
);
}
config.postcss = function(webp) {
let cssnanoOpt = {
discardUnused: false,
zindex: false
};
let rucksackOpt = { autoprefixer: true };
let devPlugins = [
postcssImport({ addDependencyTo: webp }),
mixins,
nested,
simpleVars,
rucksack(rucksackOpt),
cssnext
];
let prodPlugins = [cssnano(cssnanoOpt)];
let plugins;
if (isBuild) {
plugins = devPlugins;
} else {
plugins = devPlugins.concat(prodPlugins);
}
return plugins;
};
config.module.preLoaders = [esLintPreLoader];
config.module.loaders = [jsLoader, cssLoader, htmlLoader, filesLoader];
if (isBuild || isDevProd) {
config.plugins.push(new ExtractTextPlugin(minCss));
}
if (isDevProd || isDev) {
config.module.loaders.push(vendorsCssLoader);
}
return config;
}
我不知道,但也许这不是 webpack 的责任。无论如何,如果有任何信息可以让我摆脱这个障碍,我会非常高兴。
快速查看您的 webpack 配置,我发现 CommonsChunks 插件存在错误。您将生成的 CommonsChunks 文件命名为与输出条目文件相同的名称。因此输出文件(包含您的代码)正在被 CommonsChunks 文件替换。
如果您正在制作要分发的库,则不需要供应商文件,因此我会尝试删除 CommonsChunk 插件并查看它是否有效。
首先我得说我是一个 webpack 新手,我已经使用这个很棒的工具大约 2 周了,除了这个我已经设法实现了我需要的一切。
事情是这样的:在我的公司,我们正试图将一组通用的输入、组件和通用 css 抽象到托管在单独存储库中的模块,以便它可以作为我们其他模块中的供应商, 它叫做 Mandioca。我们所有的应用程序都是使用 Angularjs 框架开发的,因此它是一个 angular 模块。
我将所有内容捆绑在一个包含所有 .js
文件的缩小文件中,并将其输出到名为 dist
的文件夹中。没什么大不了的。
当我尝试在任何其他模块中导入 mandioca 时会出现此问题。我收到此异常:TypeError: Failed to construct 'WebSocket': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
我认为这是缩小文件中的问题,因为当我停止在模块的依赖项上导入 Mandioca 时,错误消失了:
// Exception :(
angular.module('app', [
'Mandioca',
// (...other dependencies)
]);
// Everything OK
angular.module('app', [
// (...other dependencies)
]);
我深入研究了 webpack 配置文档和 angular + webpack cookbook,发现了一些有趣的东西,但遗憾的是没有解决我的问题:
指定 externals
:
externals: {
angular: 'angular',
}
指定 output
libraryTarget 选项:
config.output = {
path: path.join(__dirname, distFolder),
filename: (isBuild ? minJs : '[name].bundle.js'),
libraryTarget: 'umd' // <--- here's the tweak
};
其他一些注意事项:
- Mandioca 模块正常运行开发任务,使用缩小文件进行开发也没有崩溃。
- 所有其他模块正常运行开发任务
- 我正在使用 webpack-dev-server 来完成这些任务。
Mandioca 的 Webpack 文件:
// webpack stuff
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import WebpackNotifierPlugin from 'webpack-notifier';
// import CopyWebpackPlugin from 'copy-webpack-plugin';
// postcss
import rucksack from 'rucksack-css';
import cssnano from 'cssnano';
import nested from 'postcss-nested';
import mixins from 'postcss-mixins';
import simpleVars from 'postcss-simple-vars';
import cssnext from 'postcss-cssnext';
import postcssImport from 'postcss-import';
import vendors from './vendors.json';
import path from 'path';
export default function makeWebpackConfig(options) {
const vendorsDir = path.join(__dirname, 'node_modules');
const excludeVendors = /node_modules/;
const distFolder = 'dist';
const minJs = 'mandioca.min.js';
const minCss = 'mandioca.min.css';
const devEntry = './app/app.dev.js';
const distEntry = './app/app.dist.js';
const isTest = !!options.TEST;
const isBuild = !!options.BUILD;
const isDev = !isBuild && !!options.DEV;
const isDevProd = isBuild && !!options.DEV;
const getCssLoader = (build) => {
let baseStr = 'css?sourceMap!postcss';
return build ? ExtractTextPlugin.extract('style', baseStr) : 'style!' + baseStr;
};
const esLintPreLoader = {
test: /\.js$/,
loader: 'eslint',
exclude: excludeVendors
};
const jsLoader = {
test: /\.js$/,
loaders: ['ng-annotate', 'babel'],
exclude: excludeVendors
};
const cssLoader = {
test: /\.css$/,
loader: getCssLoader(isBuild),
exclude: excludeVendors
};
const vendorsCssLoader = {
test: /\.css$/,
loader: 'style!css?sourceMap',
include: excludeVendors
};
const filesLoader = {
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
loader: 'file',
exclude: excludeVendors
};
const htmlLoader = {
test: /\.html$/,
loaders: ['ngtemplate', 'html'],
exclude: excludeVendors
};
const config = {
resolve: {
alias: {}
},
plugins: [],
entry: {
app: ((isBuild && !isDevProd) ? distEntry : devEntry),
vendor: []
},
module: {},
externals: {
angular: 'angular',
}
};
config.output = {
path: path.join(__dirname, distFolder),
filename: (isBuild ? minJs : '[name].bundle.js'),
libraryTarget: 'umd'
};
if (!isBuild && (isDev || isDevProd)) {
config.module.noParse = [];
vendors.forEach((vendor) => {
let vendorPath = path.resolve(vendorsDir, vendor);
// config.module.noParse.push(vendorPath);
config.entry.vendor.push(vendorPath);
config.resolve.alias[vendor.split(path.sep)[0]] = vendorPath;
});
}
if (!isTest) {
// Reference: https://github.com/ampedandwired/html-webpack-plugin
// Render index.html
config.plugins.push(
new HtmlWebpackPlugin({
template: './index.html',
inject: true,
production: isBuild,
}),
new webpack.ProvidePlugin({
moment: 'moment',
R: 'ramda',
CPF: 'cpf_cnpj'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: (isBuild && !isDevProd) ? minJs : '[name].bundle.js',
}),
// Reference: https://github.com/Turbo87/webpack-notifier
// Pops a notification on error
new WebpackNotifierPlugin(),
new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }})
);
}
config.postcss = function(webp) {
let cssnanoOpt = {
discardUnused: false,
zindex: false
};
let rucksackOpt = { autoprefixer: true };
let devPlugins = [
postcssImport({ addDependencyTo: webp }),
mixins,
nested,
simpleVars,
rucksack(rucksackOpt),
cssnext
];
let prodPlugins = [cssnano(cssnanoOpt)];
let plugins;
if (isBuild) {
plugins = devPlugins;
} else {
plugins = devPlugins.concat(prodPlugins);
}
return plugins;
};
config.module.preLoaders = [esLintPreLoader];
config.module.loaders = [jsLoader, cssLoader, htmlLoader, filesLoader];
if (isBuild || isDevProd) {
config.plugins.push(new ExtractTextPlugin(minCss));
}
if (isDevProd || isDev) {
config.module.loaders.push(vendorsCssLoader);
}
return config;
}
我不知道,但也许这不是 webpack 的责任。无论如何,如果有任何信息可以让我摆脱这个障碍,我会非常高兴。
快速查看您的 webpack 配置,我发现 CommonsChunks 插件存在错误。您将生成的 CommonsChunks 文件命名为与输出条目文件相同的名称。因此输出文件(包含您的代码)正在被 CommonsChunks 文件替换。
如果您正在制作要分发的库,则不需要供应商文件,因此我会尝试删除 CommonsChunk 插件并查看它是否有效。