初步总结上一篇文章介绍了目前前端流行的各种编辑器,以及各种流行的打包方式。最后给了一个Gulp的例子,这个是2014年写的,还有一定的优化空间,就不讨论了。这篇文章主要讲一下目前火热的打包构建方式——Webpack的使用。主菜--无开胃汤其实关于Webpack的入门指南文章有很多,配置方法也不尽相同。这里推荐一下Webpack入门指南。了解各个配置含义的开发者可以阅读本文,扫盲。毕竟我的文章不是特别基础。1.base.jsvarpath=require('path')varbaseConfig={resolve:{extensions:['','.js'],fallback:[path.join(__dirname,'../node_modules')],别名:{'src':path.resolve(__dirname,'../src'),'assets':path.resolve(__dirname,'../src/assets'),'components':path.resolve(__dirname,'../src/components')}},module:{loaders:[{test:/\.js$/,loader:'babel',exclude:/node_modules/},{test:/\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)(\?.*)?$/,loader:'url?limit=8192&context=client&name=[path][name].[hash:7].[ext]'},{test:/\.css$/,loader:'style!css!auto??prefixer',},{test:/\.scss$/,loader:'style!css!auto??prefixer!sass'}]}};module.exports=baseConfig;解读这个基础配置:1.resolve解析模块依赖时,受影响的配置项。extensions决定了哪些文件后缀在引用的时候可以省略,Webpack帮你补全名字。fallback当webpack在根目录(默认当前文件夹,绝对路径)和modulesDirectories(默认当前文件夹,相对路径)配置下找不到相关模块时,到哪个文件夹找快速指向文件路径,节省大量代码,而且不用关心层级关系。需要注意的是在scss等css预编译的引用中要加上~,这样才能让加载器识别它是别名引用路径。2.该模块分析不同的文件使用了哪些加载器。这个比较简单。文章很多,就不多说了。注意这里的scss可以换成自己的预编译器,比如:sass、less、stylus等,或者直接用postcss,当然也可以用通用的方法,后面会补充。2.开发环境配置--configvarwebpack=require('webpack');varpath=require('path')varmerge=require('webpack-merge')varbaseConfig=require('./webpack.base')vargetEntries=require('./getEntries')varhotMiddlewareScript='webpack-hot-middleware/client?reload=true';varassetsInsert=require('./assetsInsert')module.exports=merge(baseConfig,{entry:getEntries(hotMiddlewareScript),devtool:'#eval-source-map',output:{filename:'./[name].[hash].js',path:path.resolve('./dist'),publicPath:'./dist'},插件:[newwebpack.DefinePlugin({'process.env':{NODE_ENV:'"development"'}}),newwebpack.optimize.OccurenceOrderPlugin(),newwebpack.HotModuleReplacementPlugin(),newwebpack.NoErrorsPlugin(),newassetsInsert()]})先说一下这个配置的一些难点:1.getEntries是用来配置入口文件的。一般很多人手写,或者SPA页面只有一个entry,写出来很容易,但是在公司很多情况下,是需要Multipleentry的,也就是多路由Urls。这时候入口的配置就比较麻烦了。这里我把配置放在一个文件中。我们公司是按规定执行的,就是一个文件夹下的所有main.js都认为是入口文件,其他的忽略不计。functiongetEntry(hotMiddlewareScript){varpattern=paths.dev.js+'project/**/main.js';vararray=glob.sync(pattern);varnewObj={};array.map(function(el){varreg=newRegExp('project/(.*)/main.js','g');reg.test(el);if(hotMiddlewareScript){newObj[RegExp.$1]=[el,hotMiddlewareScript];}else{newObj[RegExp.$1]=el;}});returnnewObj;}2.assetsInsert用于模板替换,一个将模板中的值替换为打包后的css或js的小插件。三、打包环境配置--productionvarwebpack=require('webpack');varpath=require('path')varmerge=require('webpack-merge')varbaseConfig=require('./webpack.base')vargetEntries=require('./getEntries')varExtractTextPlugin=require('extract-text-webpack-plugin');varassetsInsert=require('./assetsInsert')varproductionConf=merge(baseConfig,{entry:getEntries(),output:{filename:'./[name].[hash].js',path:path.resolve('./public/dist'),publicPath:'./'},plugins:[newwebpack.DefinePlugin({'process.env':{NODE_ENV:'"production"'}}),newExtractTextPlugin('./[name].[hash].css',{allChunks:true}),newwebpack.optimize.UglifyJsPlugin({compress:{warnings:false}}),newwebpack.optimize.OccurenceOrderPlugin(),newassetsInsert()]})productionConf.module.loaders=[{test:/\.js$/,loader:'babel',exclude:/node_modules/},{test:/\.(png|jpe?g|gif|svg|woff2?|eot|ttf|otf)(\?.*)?$/,loader:'url?limit=8192&context=client&name=[path][name].[hash:7].[ext]'},{test:/\.css$/,loader:ExtractTextPlugin.extract('style','css'),},{test:/\.scss$/,loader:ExtractTextPlugin.extract('style','css!sass')}]module.exports=productionConf基本如下开发都差不多,区别是:1.使用ExtractTextPlugin打包css,所以需要干掉原来的baseloader,在底层写一个新的2.UglifyJsPlugin对js的代码进行了压缩。没有别的解释,一样的。4.构建命令require('shelljs/global')env.NODE_ENV='production'varora=require('ora')varwebpack=require('webpack')varwebpackConfig=require('./webpack.production.config')varspinner=ora('buildingforproduction...')spinner.start()varstaticPath=__dirname+'/../public/dist/'rm('-rf',staticPath)mkdir('-p',staticPath)webpack(webpackConfig,功能(错误,统计){spinner.stop()if(错误)throwerrprocess.stdout.write(stats.toString({colors:true,modules:false,children:false,chunks:false,chunkModules:false})+'\n')})写一个build.js,然后在package.json中添加脚本参数"build":"nodebuild.js"//这里记得写自己的build.js路径甜点(马卡龙)--有点累上面的配置可以改。比如在loaders中加入{test:/\.vue$/,loader:'vue'},就可以变成支持.vue文件的vuejs包构建。同样,修改它支持jsx,并添加一些reactjs模块,它可以用来运行Reactjs。你也可以随意更改Css预编译器的类型,喜欢什么就用什么,或者用我们前面提到的方法配置所有类型,varpath=require('path')varconfig=require('../config')varExtractTextPlugin=require('extract-text-webpack-plugin')exports.assetsPath=function(_path){returnpath.posix.join(config.build.assetsSubDirectory,_path)}exports.cssLoaders=function(options){选项=选项||{}//generateloaderstringtobeusedwithextracttextpluginfunctiongenerateLoaders(loaders){varsourceLoader=loaders.map(function(loader){varextraParamCharif(/\?/.test(loader)){loader=loader.replace(/\?/,'-loader?')extraParamChar='&'}else{loader=loader+'-loader'extraParamChar='?'}returnloader+(options.sourceMap?extraParamChar+'sourceMap':'')}).join('!')if(options.extract){returnExtractTextPlugin.extract('vue-style-loader',sourceLoader)}else{return['vue-style-loader',sourceLoader].join('!')}}//http://vuejs.github.io/vue-loader/configurations/extract-css.htmlreturn{css:generateLoaders(['css']),postcss:generateLoaders(['css']),less:generateLoadersrs(['css','less']),sass:generateLoaders(['css','sass?indentedSyntax']),scss:generateLoaders(['css','sass']),stylus:generateLoaders(['css','stylus']),style:generateLoaders(['css','stylus'])}}//生成standalonestylefiles(outsideof.vue)exports.styleLoaders=function(options){varoutput=[]varloaders=exports.cssLoaders(options)for(varextensioninloaders){varloader=loaders[extension]output.push({test:newRegExp('\\.'+extension+'$'),loader:loader})}returnoutput}这是把所有的预编译的css已添加到配置中。总结——付出代价。不知道,搞得大家一头雾水。我的经验是多尝试和测试,自己多写,看看命令行打印的错误,找出原因。看到错误时不要惊慌。很多新手最容易犯错,一看到报错就怀疑人生。您必须阅读错误报告记录。一般都有提示。只需按照提示解决相应的问题即可。
