web前端打包报错 webpack构建前端项目 打包成功但是会报错 怎么解决

webpack 前端工程化之路
近两年最流行的打包工具莫过于webpack了,之前抽时间学习了一下,想要替代之前以gulp为主的前端资源打包的工作。
这里需要实现js组件或文件版本号管理,非覆盖式发布,生成资源配置文件asset.js.json供php后端读取配置动态输出资源路径,减少后端人员误操作引起前端方面的种种Bug。
=======================================================================================================
每个页面通常包含类库文件 (libs.js),公共js(common.js)&&,组件js(如:dialog.js,select.js....), 和自身业务js文件。
其中 公共js,组件js全局只维护一个,单独成一个请求,防止依赖打包后如果有修改涉及到修改的都要重新打包的问题。
=======================================================================================================
首先建一个 demo目录 目录结构如下:
页面 home.search.html 有一个按钮,点击按钮弹出一个自定义的对话框 $.dialog()&&显示URL指定key的参数值,并异步加载 underscore.js
home.search.html:
static/js/page/home/search.js :
webpack配置文件 webpack.home.search.js
这里把 Jquery 抛出在全局使用,dialog弹窗挂载在jquery 下
javascript 代码
var webpack = require('webpack');
var path = require('path');
var AssetsPlugin = require('assets-webpack-plugin');
var jsModule = &home&;
var jsPage = &search&;
module.exports = {
libs:[&./static/js/libs/jquery/jquery.js&],
dialog:&./static/js/component/dialog/main.js&,
common:&./static/js/common/common.js&,
[jsPage.toString()]:&./static/js/page/&+jsModule+&/&+jsPage,
path: path.resolve(__dirname, &asset/js/page/&+jsModule+&/&),
filename: &[name]-[chunkhash:8].js&,
publicPath:&asset/js/page/&+jsModule+&/&,
chunkFilename:&[name]-[chunkhash:8].js&
resolve: {
'jquery': path.join(__dirname,&./static/js/libs/jquery/jquery.js&),
'underscore': path.join(__dirname,&./static/js/libs/underscore/underscore.js&)
loaders: [
{test: /\.js$/, loaders: [&babel&], exclude: /node_modules/ },
{test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'},
test: /\.css$/,
loader: &style!css&
plugins: [
new webpack.ProvidePlugin({
jQuery:path.join(__dirname,&./static/js/libs/jquery/jquery.js&),
$: path.join(__dirname,&./static/js/libs/jquery/jquery.js&),
'window.jQuery':path.join(__dirname,&./static/js/libs/jquery/jquery.js&)
new monsChunkPlugin(&libs&,jsPage+'-[name]-[chunkhash:8].js'),
new AssetsPlugin({
prettyPrint: true,
update:true,
filename: path.join(__dirname,'assets.js.json'),
processOutput: function (assets) {
return JSON.stringify(assets);
运行webpack webpack.home.search.js 生成asset目录 和 资源表asset.js.json文件:
这是asset.json 文件,格式化之后:
在home.search.html文件引入js资源文件(按先后顺序引入):
运行html点击按钮 弹出了url上key的参数:
对于只有简单的小项目来说基本满足了需求。
对于稍大的项目来说问题出来了?
&&1.assets-webpack-plugin 生成的资源路径json对象,没有明显的模块区分,如果多个模块下都有 search.js 就麻烦了
&&2.assets-webpack-plugin 生成的资源路径json对象没有顺序可言,后端动态输出后JS有可能会报错
&&3.如果使用了异步加载,assets-webpack-plugin 也会生成该路径到.json文件如上underscore.js,动态输出时也一并输出请求了,这是不允许的。
&&4.如果有多个页面都引入了dialog.js,后面发现dialog.js有Bug要修改,这下就麻烦了,涉及到的页面都要重新打包才能生效。
我们需要的资源列表:
json 代码{
&search&: {
&libs&: &.....js&,
&common&: &true&,
&search&: &.......js&
&article&: {
&libs&: &.........js&,
&common&: &true&,
&article&: &...........js&,
&dialogs&: &true&
&common&: &.....542a4.js&,
&dialogs&: &......820d8.js&
=================================================================================================== 注解:
home模块,user模块下分别有搜索页和文章页(同名的业务js)。
全局公共模块common.js,dialog.js... 置于json对象顶级,全站共同维护一份,以防有修改后涉及到的业务重新打包的问题
页面如果使用该全局模块,直接配置成true,后端判断为true直接查找顶级同名属性动态输出即可。
===================================================================================================
assets-webpack-plugin-new:
针对上面的问题必须对assets-webpack-plugin插件增加一些功能,这里保存了原插件所有原有的功能,添加了一些没有的功能,提交合并无果,索性发布一个&&
添加功能:
&&1.忽略模块:打包后忽略要生成到资源路径.json文件的模块 如:异步加载的不能同步输出路径
&&2.模块排序:按先后顺序排列资源路径,以便于后端动态输出
&&3.公共模块:全站公共模块维护一份
&&4.打包模块:如:user 模块
&&5.入口文件: 如:user/main.js
安装 npm install assets-webpack-plugin-new --save ,
修改 webpack.home.search.js 配置文件,require('assets-webpack-plugin-new') ,修改 new AssetsPlugin({}) 里面的配置参数:
删除根目录下的 asset.js.json文件 或设 new AssetsPlugin({update:false});
再次运行 webpack webpack.home.search.js 成功后生成 asset.js.json 文件如下:
里面没有了异步加载的underscore.js路径,公共模块置于对象顶层, 按照我们想的顺序排列了,php 可以直接读取输出。
按照这样我们再测试一个用户中心下面的添加文章页面点击按钮显示用户信息,这儿做法同理只需要修改相应的配置,就不再显示详细代码直接看生成的asset.js.json文件结果:
这得到了我们想要的结果。。。。但是发现了一个问题打包后 common.js,和 dialog.js 的版本号在变化,我并没有修改里面的代码,虽然不影响使用,但这也是不允许的!!!!
这是webpack 一个机制问题,这里就不讨论了 怎么解决呢??
这里我使用了一个 webpack-md5-hash 插件,引入webpack-md5-hash 在plugins里面使用 new WebpackMd5Hash() 这样每次得到的就相同了,到此就解决了该问题。
当然这还有很多优化的地方,比如 jquery 也可以直接放在全局里,home,user配置文件可以是一个。。。。。。
后端读取配置:
这里面简单使用 thinkphp 演示 (部分代码)
====================================================================================================
Controller:
====================================================================================================
这样站点静态资源统一由前端提供资源配置表.json文件,php后端动态读取输出JS路径就完成了!
挺完整的,等会配个试试。。。
火钳刘明!点赞!
3 总笔记数
483 总阅读量
Copyright &
All Rights Reserved.
合作伙伴:1383人阅读
前端自动化构建工具(gulp+webpack)(2)
这几天写腾讯实习生 Mini 项目的时候用上了 React 全家桶,当然同时引入了 Webpack 作为打包工具。但是开发过程中遇到一个很棘手的问题就是,React 加上 React-Router、superagent、eventproxy 这些第三方轮子一共有好几百个 module,Webpack 的打包速度极慢。这对于开发是非常不好的体验,同时效率也极低。
我们先来看一下完全没有任何优化的时候,Webpack 的打包速度(使用了jsx和babel的loader)。下面是我们的测试文件:
var react = require('react');
var ReactAddonsCssTransitionGroup = require('react-addons-css-transition-group');
var reactDOM = require('react-dom');
var reactRouter = require('react-router');
var superagent = require(&superagent&);
var eventproxy = require(&eventproxy&);
webpack&test.js
在我的2015款RMBP13,i5处理器,全SSD下,性能是这样的:
没错你没有看错,这几个第三方轮子加起来有整整668个模块,全部打包需要20多秒。
这意味着什么呢?你每次对业务代码的修改,gulp 或者 Webpack 监测到后都会重新打包,你要足足等20秒才能看到自己的修改结果。
但是需要重新打包的只有你的业务代码,这些第三方库是完全不用重新打包的,它们的存在只会拖累打包性能。所以我们要找一些方法来优化这个过程。
Webpack 可以配置 externals 来将依赖的库指向全局变量,从而不再打包这个库,比如对于这样一个文件:
import React from 'react';
console.log(React);
如果你在 Webpack.config.js 中配置了externals:
module.exports = {
externals: {
'react': 'window.React'
等于让 Webpack 知道,对于&react&这个模块就不要打包啦,直接指向&window.React&就好。不过别忘了加载
react.min.js,让全局中有&React&这个变量。
我们来看看性能,因为不用打包 React 了所以速度自然超级快,包也很小:
问题如果就这么简单地解决了的话,那我就没必要写这篇文章了,下面我们加一个 react 的动画库 react-addons-css-transition-group 来试一试:
import React from 'react';
import ReactAddonsCssTransitionGroup from 'react-addons-css-transition-group';
console.log(React);
对,你没有看错,我也没有截错图,新加了一个很小很小的动画库之后,性能又爆炸了。从模块数来看,一定是 Webpack 又把 react 重新打包了一遍。
我们来看一下为什么一个很小很小的动画库会导致 Webpack 又傻傻地把 react 重新打包了一遍。找到 react-addons-css-transition-group 这个模块,然后看看它是怎么写的:
module.exports = require('react/lib/ReactCSSTransitionGroup');
这个动画模块就只有一行代码,唯一的作用就是指向 react 下面的一个子模块,我们再来看看这个子模块是怎么写的:
var React = require('./React');
var ReactTransitionGroup = require('./ReactTransitionGroup');
var ReactCSSTransitionGroupChild = require('./ReactCSSTransitionGroupChild');
这个子模块又反回去依赖了 react 整个库的入口,这就是拖累 Webpack 的罪魁祸首。
总而言之,问题是这样产生的:
Webpack 发现我们依赖了 react-addons-css-transition-group
Webpack 去打包 react-addons-css-transition-group 的时候发现它依赖了 react 模块下的一个叫 ReactTransitionGroup.js 的文件,于是 Webpack 去打包这个文件。
ReactTransitionGroup.js 依赖了整个 react 的入口文件 React.js,虽然我们设置了 externals ,但是 Webpack 不知道这个入口文件等效于 react 模块本身,于是我们可爱又敬业的 Webpack 就把整个 react 又重新打包了一遍。
读到这里你可能会有疑问,为什么不能把这个动画库也设置到 externals 里,这样不是就不用打包了吗?
问题就在于,这个动画库并没有提供生产环境的文件,或者说这个库根本没有提供 react-addons-css-transition-group.min.js 这个文件。
这个问题不只存在于 react-addons-css-transition-group 中,对于 react 的大多数现有库来说都有这个依赖关系复杂的问题。
所以对于这个问题的解决方法就是,手工打包这些 module,然后设置 externals ,让 Webpack 不再打包它们。
我们需要这样一个&lib-bundle.js&文件:
window.__LIB[&react&] = require(&react&);
window.__LIB[&react-addons-css-transition-group&] = require(&react-addons-css-transition-group&);
我们在这里把一些第三方库注册到了&window.__LIB&下,这些库可以作为底层的基础库,免于重复打包。
然后执行&webpack lib-bundle.js lib.js,得到打包好的&lib.js。然后去设置我们的
externals :
var webpack = require('webpack');
module.exports = {
externals: {
'react': 'window.__LIB[&react&]',
'react-addons-css-transition-group': 'window.__LIB[&react-addons-css-transition-group&]',
这时由于 externals 的存在,Webpack 打包的时候就会避开这些模块超多,依赖关系复杂的库,把这些第三方 module 的入口指向预先打包好的&lib.js&的入口&window.__LIB,从而只打包我们的业务代码。
上面我们提到的方法本质上就是一种动态链接库(dll)”的思想,这在 windows 系统下面是一种很常见的思想。一个dll包,就是一个很纯净的依赖库,它本身不能运行,是用来给你的 app 或者业务代码引用的。
同样的 Webpack 最近也新加入了这个功能:webpack.DllPlugin。使用这个功能需要把打包过程分成两步:
引用ddl包,打包业务代码
首先我们来打包ddl包,首先配置一个这样的&ddl.config.js:
const webpack = require('webpack');
const vendors = [
'react-dom',
'react-router',
module.exports = {
path: 'build',
filename: '[name].js',
library: '[name]',
&lib&: vendors,
plugins: [
new webpack.DllPlugin({
path: 'manifest.json',
name: '[name]',
context: __dirname,
webpack.DllPlugin 的选项中:
path&是&manifest.json&文件的输出路径,这个文件会用于后续的业务代码打包;
name&是dll暴露的对象名,要跟&output.library&保持一致;
context&是解析包路径的上下文,这个要跟接下来配置的
webpack.config.js 一致。
运行Webpack,会输出两个文件一个是打包好的&lib.js,一个就是&manifest.json,它里面的内容大概是这样的:
&name&: &vendor_ac51ba426d4f259b8b18&,
&content&: {
&./node_modules/react/react.js&: 1,
&./node_modules/react/lib/React.js&: 2,
&./node_modules/react/node_modules/object-assign/index.js&: 3,
&./node_modules/react/lib/ReactChildren.js&: 4,
&./node_modules/react/lib/PooledClass.js&: 5,
&./node_modules/react/lib/reactProdInvariant.js&: 6,
接下来我们就可以快乐地打包业务代码啦,首先写好打包配置文件&webpack.config.js:
const webpack = require('webpack');
module.exports = {
path: 'build',
filename: '[name].js',
app: './src/index.js',
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./manifest.json'),
webpack.DllReferencePlugin 的选项中:
context&需要跟之前保持一致,这个用来指导
Webpack 匹配&manifest&中库的路径;
manifest&用来引入刚才输出的&manifest.json&文件。
DllPlugin 本质上的做法和我们手动分离这些第三方库是一样的,但是对于包极多的应用来说,自动化明显加快了生产效率。
其实还有一个速度的优化点,就是配置babel,让它排除一些文件,当loader这些文件时不进行转换,自动跳过;可在.babelrc文件中配置,示例:
&presets&: [
&ignore&:[
&jquery.js&,
&jquery.min.js&,
&angular.js&,
&angular.min.js&,
&bootstrap.js&,
&bootstrap.min.js&
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:31717次
排名:千里之外
原创:36篇
转载:83篇
本博客从2015年5月开始,虽然写的东西都比较基础,但还是希望能帮助一些人,另一方面也算是对自己学习的一种监督吧!webpack -p压缩打包react报语法错误处理
前言:在用webpack打包react代码的时候发现一个问题,做一个处理总结。
我的webpack配置:
var webpack = require("webpack");
//打包less插件
var ExtractTextPlugin = require("extract-text-webpack-plugin");
//这里的"./css/bundle.css"设置打包地址
var ExtractLess = new ExtractTextPlugin("./css/bundle.css");
//打包多个文件插件
//var commonsPlugin = new monsChunkPlugin("common.js");
var path = require("path");
module.exports = {
"./reactDom/index.js"
path:"./build",
filename:"indexReact.js"
{test: /\.js$/, exclude: /(node_modules|bower_components)/, loader: "babel",query:{presets:["es2015","react"]}},
{test:/\.less$/,loader:ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")},
//图片文件使用 url-loader 来处理,小于8kb的直接转为base64
{ test: /\.(png|jpg)$/, loader: "url-loader?q=8192"}
extensions:["",".js"]
ExtractLess,
上面看上去一切正常,运行webpack -w时候也没有任何问题
&&&&&&&&&&&&&&&&&&&&&&&&&&&&
但是如果我使用-p压缩的话就会报错:
&&&&&&&&&&&&&&&&&&&&&&&&&&&&来源:互联网 更新时间: 21:42:22 责任编辑:鲁晓倩字体:
有用户碰到这样的问题:reactjs中用webpack预处理并打包jsx后浏览器访问时不报错,但也什么都不显示,具体问题如下:
3 小时前提问
相关文章:
上一篇文章:关于类数组对象的问题?下一篇文章:关于多点触控问题
最新添加资讯
24小时热门资讯
Copyright ©
All Rights Reserved. 中国学网 版权所有
京ICP备号-1 京公网安备02号彻底解决 webpack 打包文件体积过大 - 简书
下载简书移动应用
写了4610字,被23人关注,获得了50个喜欢
彻底解决 webpack 打包文件体积过大
webpack 把我们所有的文件都打包成一个 JS 文件,这样即使你是小项目,打包后的文件也会非常大。下面就来讲下如何从多个方面进行优化。
去除不必要的插件
刚开始用 webpack 的时候,开发环境和生产环境用的是同一个 webpack 配置文件,导致生产环境打包的 JS 文件包含了一大堆没必要的插件,比如 HotModuleReplacementPlugin, NoErrorsPlugin... 这时候不管用什么优化方式,都没多大效果。所以,如果你打包后的文件非常大的话,先检查下是不是包含了这些插件。
提取第三方库
像 react 这个库的核心代码就有 627 KB,这样和我们的源代码放在一起打包,体积肯定会很大。所以可以在 webpack 中设置
bundle: 'app'
vendor: ['react']
plugins: {
new monsChunkPlugin('vendor',
'vendor.js')
这样打包之后就会多出一个 vendor.js 文件,之后在引入我们自己的代码之前,都要先引入这个文件。比如在 index.html 中
&script src="/build/vendor.js"&&/script&
&script src="/build/bundle.js"&&/script&
除了这种方式之外,还可以通过引用外部文件的方式引入第三方库,比如像下面的配置
externals: {
'react': 'React'
externals 对象的 key 是给 require 时用的,比如 require('react'),对象的 value 表示的是如何在 global 中访问到该对象,这里是 window.React。这时候 index.html 就变成下面这样
&script src="///react/0.14.7/react.min.js"&&/script&
&script src="/build/bundle.js"&&/script&
当然,个人更推荐第一种方式。
webpack 自带了一个压缩插件 ,只需要在配置文件中引入即可。
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
加入了这个插件之后,编译的速度会明显变慢,所以一般只在生产环境启用。
另外,服务器端还可以开启 gzip 压缩,优化的效果更明显。
什么是代码分割呢?我们知道,一般加载一个网页都会把全部的 js 代码都加载下来。但是对于 web app 来说,我们更想要的是只加载当前 UI 的代码,没有点击的部分不加载。
看起来好像挺麻烦,但是通过 webpack 的
就可以方便实现。具体的例子可以看下 react router 的官方示例 。不过这里还是讲下之前配置踩过的坑。
code split 是 ES6 的模块系统的,所以在导入和导出的时候千万要注意,特别是导出。如果你导出组件的时候用 ES6 的方式,这时候不管导入是用 CommomJs 还是 AMD,都会失败,而且还不会报错!
当然会踩到这个坑也是因为我刚刚才用 NodeJS,而且一入门就是用 ES6 的风格。除了这个之外,还有一点也要注意,在生产环境的 webpack 配置文件中,要加上 publicPath
path: xxx,
publicPath: yyy,
filename: 'bundle.js'
不然的话,webpack 在加载 chunk 的时候,路径会出错。
开始这个小节之前,可以先看下大神的一篇文章:。
对于静态文件,第一次获取之后,文件内容没改变的话,浏览器直接读取缓存文件即可。那如果缓存设置过长,文件要更新怎么办呢?嗯,以文件内容的 MD5 作为文件名就是一个不错的解决方案。来看下用 webpack 应该怎样实现
path: xxx,
publicPath: yyy,
filename: '[name]-[chunkhash:6].js'
打包后的文件名加入了 hash 值
const bundler = webpack(config)
bundler.run((err, stats) =& {
let assets = stats.toJson().assets
for (let i = 0; i & assets. i++) {
if (assets[i].name.startsWith('main')) {
name = assets[i].name
fs.stat(config.buildTemplatePath, (err, stats) =& {
if (err) {
fs.mkdirSync(config.buildTemplatePath)
writeTemplate(name)
手动调用 webpack 的 API,获取打包后的文件名,通过 writeTemplate 更新 html 代码。完整代码猛戳 。
这样子,我们就可以把文件的缓存设置得很长,而不用担心更新问题。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
· 46人关注
如果可能,愿一生作安静的码农
· 8人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:

我要回帖

更多关于 前端webpack workflow 的文章

 

随机推荐