1. webpack基础配置
webpack4.0必须安装webpack和wabpck-cli
webpack可以0配置,它默认支持js模块化,因此可以使用commonjs语法
1.基础配置项
配置文件的默认名为webpack.config.js或者webpackfile.js,(自定义名称的话可再命令中添加config参数)
- entry(入口)
Sring | Array | Object - output
output:{
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'dist') // 路径必须是绝对路径,(先引入path模块)
}
- module
- mode
- development/production
2.webpack打包出的文件解析
3.Html插件
- webpack-dev-server //模拟线上环境(不会真实打包,在内存中打包),在webpack.config.js文件中的对应字段为devServer
devServer: {
port: 3000,
progress: true, // 打包进度条
contentBase: './dist', //根地址对应路径
compress: true // 是否启用gzip压缩
},
- html-webpack-plugin // html相关的插件
plugins: [ //放着所有的webpack插件
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true
},
hash: true
})
]
4.模块处理(或者.vue,.js等等文件)
主要用于处理非js模块(es6 to es5),需要在module中配置相应处理规则和加载器,以下,先以样式处理为例子
module: {
rules: [
{
test: /\.scss$/, // sass-loader node-sass, less less-loader, stylus stylus-loader
use: [
{
loader: 'style-loader',
options: {
insertAt: 'top'
}
},
'css-loader',
'sass-loader'
]
}
]
},
style-loader会把样式以<style>标签的形式插入到head标签中,如果要将样式单独抽离成css文件,就需要用到插件‘mini-css-extract-plugin’了
let MiniCssExtractPlugin = require('mini-css-extract-plugin'); //引入插件(得先安装);
module: {
rules: [
{
test: /\.(sc|c)ss$/, // sass-loader node-sass, less less-loader, stylus stylus-loader
use: [
MiniCssExtractPlugin.loader, //此处就不用了‘style-loader’了
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'main.css'
})
]
如果用到css3的新功能,那么就需要加前缀,首先装包 postcss-loader, autoprefixer,然后需要配置postcss的config文件(postcss.config.js)
// postcss.config.js文件
module.exports = {
plugins: [require('autoprefixer')]
}
//webpack.config.js文件
module: {
rules: [
{
test: /\.(sc|c)ss$/, // sass-loader node-sass, less less-loader, stylus stylus-loader
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader', //先预处理css,得出结果后才用css-loader
'sass-loader'
]
}
]
},
如果要压缩css,首先,配置文件中,mode需设置为“production”,然后在webpack配置文件中添加字段“optimization”,用插件optimize-css-assets-plugin压缩CSS
optimization: {
minimizer: [
new OptimizeCss(),
new TerserJs({
cache: true,
sourceMap: true
})
]
}
处理js模块(es6 -> es5),首先安装模块加载器‘babel-loader’,然后安装babel核心模块“@babel/core”,最后安装转换规则(es6,es7,提案阶段...)模块,这里我们使用“@babel/preset-env”
module: {
rules: [
{
test: /\.(sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader"
]
},
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: ["@babel/plugin-proposal-class-properties"] //这个插件是为了转换es7的class语法
}
}
}
]
},
babel默认不转化新的API,需要“@babel/plugin-transform-runtime”来转化(但是比如“foobar”.includes(“foo”),Object.assign等就需要安装@babel/polyfill),这个包是开发依赖,上线也需要支持新的语法,因此还需要“@babel/runtime”,将其添加至plugins。同时,转化js应该避开node_modules
文件夹
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: [
["@babel/plugin-proposal-class-properties"],
["@babel/plugin-transform-runtime"]
]
}
},
include: path.resolve('dist'),
exclude: /node_modules/
}
4.配置eslint
eslint是js的语法校验规则,可以去官网demo处下载eslint.json文件,根据自己的需求添加校验规则。
loader的执行顺序是右向左,下向上,因此匹配到js是,先校验,然后才进行转化语法,压缩等操作,use中有字段“enforce”来指定loader执行顺序,如下
//为了灵活配置(比如后期可能不需要eslint了),因此将eslint规则单独放开
{
test: /\.js$/,
enforce: 'pre' //pre,post(此处有坑,eslint-loader文档中写的是和“loader”字段同级,经实测,可放在这里,也可放在loader的options中)
use: [
{
loader: 'eslint-loader'
}
]
},
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"],
plugins: [
["@babel/plugin-proposal-class-properties"],
["@babel/plugin-transform-runtime"]
]
}
},
include: path.resolve("src"),
exclude: /node_modules/
}
5.第三方模块的使用
我们以jquery为例
//index.js
import $ from "jquery"
console.log($)
//在做传统项目时,如果引入了jquery,那么在全局都可以使用(绑定在了window上)
//那么我们打印一下“window.$”
console.log(window.$)
window.$是undefined
此时,我们可以使用“expose-loader”,暴露全局的loader,这是内联loader。(loader类型,pre-前置,post-后置,normal-普通loader,内联loader)
import $ from "expose-loader?$!jquery";
console.log($);
console.log(window.$);
当然,也可以写成普通loader的方式
module: {
rules: [
{
test: require.resolve("jquery"),
use: "expose-loader?$"
}
]
还可以不在每个页面引入,直接把jquery集成到webpack配置中
首先引入webpack,然后调用webpack自带的providePlugin
new webpack.ProvidePlugin({
$: "jquery"
})
可是打包之后,发现bundle.js文件过大,将jquery也打包进去了,这时可以将JS引用方式改为CDN引入。
然后在webpack配置文件中添加externals字段
externals: {
jquery: "jQuery"
},
webpack在打包时,会分析每个包的依赖,像jquery这种不依赖任何包的包,解析是没有必要的,它会拖慢打包速度,这是,可以在module中添加字段“noParse”
module: {
npParse: /jquery/ //不去解析jquery的依赖库
}
6.webpack打包图片
常规项目中我们要使用image,一般有三种方式:
//1.js导入
var Img = new Image();
Img.src = './image.png';
document.body.appendChild(Img);
//2.css中元素背景
body{
background: url('./image.png') 100%/center;
}
//3.html中
<img src="./image.png">
在webpack中,如果以JS方式引用图片,得先在webpack配置文件中加上“file-loader”)
//webpack.config.js
...
modlue: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: 'url-loader'
}
]
}
...
//1.js导入
let imgFile = require('./image.png')//以模块的方式导入
var Img = new Image();
Img.src = './image.png'; //在webpack项目中,打包后以这种相对路径的方式引用图片资源是不行的,必须先以模块的方式导入(以上require)
document.body.appendChild(Img);
//2.css中引入
//因为引入了css-loade,在css文件中,“background:url('./logo.png')”会被自动转化为“background:url(require('./logo.png'))”,因此,不用做特殊处理
//3.在html中引入,同理,打包后的文件不能从“./”目录找到相应的资源,这时可以使用插件“html-withimg-loader”
//webpack.config.js
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader'
}
]
}
如果图片较小时,为了减少http请求,可以将图片转为base64,要用到加载器“url-loader”
rules: [
{
test: /\.(jpg|png|gif)$/,
// 可以给一个限制,图片大小小于某个值时,转为base64,否则会自动使用“flie-loader”将文件拷贝至生产目录。(如果想让img文件都存放在特定的文件夹中,可以指定“name”参数)
use: {
loader: 'url-loader',
options: {
limit: 200*1024,
name: image/[name].[hash:5].[ext]
}
}
}
]
// 同理,生成的css类文件也可以放在指定文件夹中,只需在文件名前加路径
plugins: [ //放着所有的webpack插件
....
new MiniCssExtractPlugin({
filename: 'css/main.css'
})
]
在浏览器中运行
6.文件分块打包
以上,在正式环境中,如果img,js,css等资源都要放到cdn服务器上,那么像“image/logo1.png”就得变成“https://xxx.xxxx.xx/image/logo1.png”这种形式。此时,可以在webpack配置文件的output中添加publicPath字段来指定域名
output: {
filename: 'bundle.[hash:5].js', //打包后的文件名
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://www.baidu.com'
},
如果只有某种文件上cdn,比如图片,可以将publicPath写到对应处理规则中,但output中的对应字段得删掉
{
test: /\.(jpg|png|gif)$/, // 可以给一个限制,图片大小小于某个值时,转为base64,否则还是使用file-loader
use: {
loader: 'url-loader',
options: {
limit: 1,
name: 'img/[name].[ext]',
publicPath: 'http://xxx.xxxx.xx'
}
}
}