webpack是一个module bundler,抛开博大精深的汉字问题,我们暂且管他叫'模块管理工具'。随着js能做的事情越来越多,浏览器、服务器,js似乎无处不在,这时,使日渐增多的js代码变得合理有序就显得尤为必要,也应运而生了很多模块化工具。从服务器端到浏览器端,从原生的没有模块系统的`<script>`到基于Commonjs和AMD规范的实现到ES6 modules。为了模块化和更好的模块化,我们总是走在探索的路上。
但是这些实现模块化的方法或多或少都有他们的缺点。比如说使用`<script>`标签导入js模块,顺序不好把握且我们需要自己梳理可能的冲突和依赖;使用Commonjs规范来解决问题,它使我们在服务器端的模块得到了重用,但是在浏览器端,网络的请求都是异步的,无法并行的require多个module。ES6 modules的实现也只是一小部分,并且想要得到所有浏览器的支持,相比还是需要相当的一段时间。
当然灵活的模块管理只是webpack的众多特性之一,它还有众多优秀的特性:
1 - 它同时支持commonjs和AMD规范(甚至混合的形式); 2 - 它可以打成一个完整的包,也可以分成多个部分,在运行时异步加载(可以减少第一次加载的时间); 3 - 依赖在编译时即处理完毕,可以减少运行时包的大小; 4 - Loaders可以使文件在编译时得到预处理,这可以帮我们做很多事情,比如说模板的预编译,图片的base64处理; 5 - 丰富的和可扩展的插件可以适应多变的需求。
一、webpack详解最近在学习ES6和React相关的知识,为了更加方便自己写代码,给自己写了个脚手架generator-reactpack。生成的项目中可以看到一个基本的webpack.config.js文件:
1 var webpack = require('webpack'); 2 module.exports = { 3 entry: [ 4 'webpack/hot/only-dev-server', 5 './js/app.js' 6 ], 7 output: { 8 path: './build', 9 filename: 'bundle.js' 10 }, 11 module: { 12 loaders: [ 13 { test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ }, 14 { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}, 15 { test: /\.css$/, loader: "style!css" }, 16 {test: /\.less/,loader: 'style-loader!css-loader!less-loader'} 17 ] 18 }, 19 resolve:{ 20 extensions:['','.js','.json'] 21 }, 22 plugins: [ 23 new webpack.NoErrorsPlugin() 24 ] 25 };
webpack.config.js文件通常放在项目的根目录中,它本身也是一个标准的Commonjs规范的模块。在导出的配置对象中有几个关键的参数:
1.entry
entry可以是个字符串或数组或者是对象。
当entry是个字符串的时候,用来定义入口文件:
1 entry: './js/main.js'
当entry是个数组的时候,里面同样包含入口js文件,另外一个参数可以是用来配置webpack提供的一个静态资源服务器,webpack-dev-server。webpack-dev-server会监控项目中每一个文件的变化,实时的进行构建,并且自动刷新页面:
1 entry: [ 2 'webpack/hot/only-dev-server', 3 './js/app.js' 4 ]
当entry是个对象的时候,我们可以将不同的文件构建成不同的文件,按需使用,比如在我的hello页面中只要\<script src='build/Profile.js'></script>引入hello.js即可:
1 entry: { 2 hello: './js/hello.js', 3 form: './js/form.js' 4 }
2.output
output参数是个对象,用于定义构建后的文件的输出。其中包含path和filename:
1 output: { 2 path: './build', 3 filename: 'bundle.js' 4 }
当我们在entry中定义构建多个文件时,filename可以对应的更改为[name].js用于定义不同文件构建后的名字。
3.module
关于模块的加载相关,我们就定义在module.loaders中。这里通过正则表达式去匹配不同后缀的文件名,然后给它们定义不同的加载器。比如说给less文件定义串联的三个加载器(!用来定义级联关系):
1 module: { 2 loaders: [ 3 { test: /\.js?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/ }, 4 { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'}, 5 { test: /\.css$/, loader: "style!css" }, 6 { test: /\.less/, loader: 'style-loader!css-loader!less-loader'} 7 ] 8 }
此外,还可以添加用来定义png、jpg这样的图片资源在小于10k时自动处理为base64图片的加载器:
1 { test: /\.(png|jpg)$/,loader: 'url-loader?limit=10000'}
给css和less还有图片添加了loader之后,我们不仅可以像在node中那样require js文件了,我们还可以require css、less甚至图片文件: