什么是webpack
webpack是一个模块打包的解决方案
webpack和gulp对比
其实没啥可比性,gulp是构建前端自动化流程的工具,而webpack只是一个模块打包的。gulp可以制定一些任务,自动执行一些操作。webpack是通过一个给定的入口主文件,然后将这个主文件内的所有依赖的文件都用loaders处理,最后打包成一个浏览器可以识别的js文件。webpack的处理速度更快,它把所有文件都当做模块处理,css以及图片等等。
基础的配置文件
module.exports = {
context:__dirname+"/app"
entry: "./main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方,相对
filename: "bundle.js"//打包后输出文件的文件名
//publicPath:'http://cdn' 一般通过比如cdn加载网络静态资源,作为前缀路径,一般生产环境会用这个替换路径
}
}
注意,“__dirname”是node.js中的一个全局变量,它指向当前执行脚本所在的目录。
当entry为数组或对象
当有多个入口vendor和index的时候,会分别从多个入口内进入,并扫描全部依赖生成一个vendor.js和index.js文件
module.exports = {
entry:{
"vendor":['jquery','abc.js'],
"index":'./public/src/index.js',
},
output:{
path:'/public',
filename:"[name].js" //vendor.js,index.js
}
}
更快捷的执行打包
有时候我们需要执行webpack —watch —xxx-xx等一系列很长的命令时,这样去敲是不太方便的,我们可以将长命令配置在package.json中,通过npm脚本执行。
{
"name": "webpack_demo",
"version": "1.0.0",
"description": "webpack_demo",
"scripts": {
"abc": "webpack xxx xxx xxx" //在此处配置,相当于把npm run abc替换成了webpack xxx
},
}
Source Maps方便调试
打包后文件出错往往找不到对应的源代码位置,Source Maps就是用来解决这个问题的,他可以帮我们映射编译文件对应源文件的位置。
module.exports = {
// 注意,source map有多种,下面这种是比较合适的
devtool:'eval-source-map',//配置生成Source Maps,
entry:__dirname + "/app/main.js",
output:{
path:__dirname + "/public",
filename:"bundle.js"
}
}
webpack构建本地服务器
通过安装webpack-dev-server的模块,然后配置devserver来开启本地服务器,它可以让浏览器检测代码修改,并自动刷新页面显示修改后的结果,它是基于node.js构建的。
module.exports = {
devServer:{
contentBase:"./public", //本地服务器所加载的页面所在的目录
colors:true, //终端中输出结果为彩色
historyApiFallback:true, //不跳转
inline:true //实时刷新
}
}
resolve
用来控制搜索路径,平常引用文件的时候路径比较长,比如./app/src/components
,现在我们可以用一个别名代替
module.exports = {
resolve:{
//默认从此处开始搜索模块
root:[
path.join(__dirname,"node_modules")
],
//别名
alias:{
js:path.join(_dirname,"../app/src/scripts")
},
//扩展文件名后缀,require模块的时候可以不写后缀名
extensions: ['', '.js', '.vue', '.scss', '.css']
}
}
现在引用文件只需要js/xxx.js
就可以了
按需加载模块
通过require.ensure
声明的文件,会被按需加载,所以这些文件必须是一个独立的个体,在需要被展示的时候才动态加载。一般路由组件的场景很多。
// 定义一个FirstPage的懒加载组件
let FirstPage = (location,cb) => {
require.ensure([],require => {
cb(null,require('../containner/xxx.js').default)//export default暴露的时候需要加一个default
},FirstPage)
}
// 在webpack的output中进行相应的配置
module.exports = {
output:{
path:__dirname + '/public/',
filename:'[name][hash].js',
chunkFilename:'[name].chunk.[hash].js',//单个文件名
sourceMapFilename: 'js/[name].js.map',//独立文件sourcemap
}
}
注意:这里[name]会被块名替换掉,[hash]会被编译的hash替换掉,其他同理。
Loaders
webpack中的核心应该就是loaders了,通过不同的loader来打包处理不同的文件,比如说将es6、es7转换成浏览器识别的样子。
loader模块需要单独安装,并且在modules
下进行配置:
-
test
:匹配一个被loader处理的文件的拓展名的正则表达式 -
loader
:loader的名称 -
include/exclude
:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹) -
query
:为loaders提供额外的设置选项()
module.exports = {
module:{
rules:[ // loaders数组,里面放的都是loader
{
test:/\.json$/,
use:[{ //注意,webpack1和webpack2的loader语法不太一样
loader:"json-loader",
options:{xxx:"xxx",aaa:'aaa'}//向json-loader上配置参数。
//loader:"json?xxx=xxx&aaa=aaa" //还可以这样配置参数
}]
}
]
}
}
Babel
babel是一个比较复杂的loader,它可以编译es6,es7,jsx。
module.exports = {
module:{
rules:[
{
test:/\.js|jsx$/,
exclude:/node_modules/, //不处理node_modules这个文件夹,这里不需要引号
use:[{
loader:'babel-loader',
options:{presets:['es2015','react']}
}],
}
]
}
}
Babel配置选项
babel有自己的配置项,一般都会把babel的配置项放在一个名为“.babelrc”的配置文件中.
{
"presets":["react","es2015"]
}
css
webpack提供两个工具处理样式表,css-loader
和style-loader
,[css-loader][]可以让我们使用@import
和url(...)
的方法实现require()
的功能,比如在react中,我们直接通过import 'xxx.css'
来引入css,style-loader
可以将所有的计算后的样式加入页面的内联样式中。
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
}
}
注意:style!css中,加感叹号的作用在于使同一文件能够使用不同类型的loader
多个loader可以用在同一个文件上并且被链式调用,链式调用时从右到左执行且loader之间用“!”来分割。
- webpack在入口文件内搜索依赖项,发现有css依赖。
- css文件交给css-loader去处理
- css处理完之后,webpack将处理结果交给style-loader去处理
CSS module
可以让css产生作用域的效果即scope
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader?module'] //在css加载器后面加了一个module
}
]
}
}
现在创建一个root.css文件
.root{background-color:red}
在jsx中引入
import React from 'react';
import './root.css';
export default class liberty extends React.Component{
render(){
return (
<div className = 'root'> // 添加类名
</div>
)
}
}
这个时候,其他组件如果也要使用root这个类名,不会造成污染。
自动添加css兼容性前缀
需要[postcss-loader][]和[autoprefixer][]插件
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:['style-loader','css-loader?module!postcss']
}
]
},
postcss:[
require('autoprefixer') //调用autoprefixer插件
]
}
常用命令
$ webpack --config webpack.min.js //另一份配置文件,作为生产和开发环境的区分
$ webpack --display-error-details //显示异常信息
$ webpack --watch //监听变动并自动打包
$ webpack -p //压缩混淆脚本,这个非常非常重要!
$ webpack -d //生成map映射文件,告知哪些模块被最终打包到哪里了
常用插件
ExtractTextPlugin:可以从bundle中提取出特定的内容到一个文件中,可以抽离公共样式
let ExtractTextPlugin = require("extract-text-webpack-plugin");
let extractCSS = new ExtractTextPlugin('stylesheets/[name].css');
module.exports = {
module:{
rules:[
{
test:/\.css/,
use:extractCSS.extract(['css','sass'])
}
]
}
plugins:[
extractCSS
]
}
CommonsChunkPlugin:可以将多个入口中的公共内容提取出来。
CommonsChunk:可以用来解决多个js引用了同一个文件导致该文件多次请求的情况,它会把这个文件打包进一个公共的文件内,被浏览器缓存。
module.exports = {
plugins:[
new webpack.optimize.CommonsChunkPlugin({
name:"commons",
filename:"commons.js",
minChunks:2 //加载次数
})
]
}
现在的如果有任意模块被加载了两次或更多,它就会被打包进一个叫commons.js
的文件里。