webpack基础配置教程
1. 初识Webpack
- 什么是webpack?
- Webpack是一个模块打包器。
- 在Webpack中会将前端的所有资源文件(js/json/css/img/less/…)都作为模块处理。
- 它将根据模块的依赖关系进行分析,生成对应的资源
- 五个核心概念:
- 【入口(entry)】:指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。
- 【输出(output)】:在哪里输出文件,以及如何命名这些文件。
- 【Loader】:处理那些非 JavaScript 文件(webpack 自身只能解析 JavaScript和json)。
- 【插件(plugins)】执行范围更广的任务,从打包到优化都可以实现。
- 【模式(mode)】,有生产模式production和开发模式development
- 对loader的理解
- webpack 本身只能处理JS、JSON模块,如果要加载其他类型的文件(模块),就需要使用对应的loader 。
- 它本身是一个函数,接受源文件作为参数,返回转换的结果。
- loader 一般以 xxx-loader 的方式命名,xxx 代表了这个 loader 要做的转换功能,比如 css-loader。
- 对plugins的理解
- 插件可以完成一些loader不能完成的功能。
- 配置文件
- webpack.config.js : 用于存储webpack配置信息。
2. 开启项目
初始化项目:
使用
1
npm init
或
1
yarn init
生成一个package.json文件
1
2
3
4
5{
"name": "webpack_test",
"version": "1.0.0"
}
复制代码
安装webpack
- npm install webpack@4 webpack-cli@3 -g //全局安装,作为指令使用
- npm install webpack@4 webpack-cli@3 -D //本地安装,作为本地依赖使用
3. 处理js和json文件
创建js文件
- src/js/app.js
- src/js/module1.js
- src/js/module2.js
创建json文件
- src/json/data.json
创建主页面:
- src/index.html
运行指令
打包指令(开发):
1
2webpack ./src/js/app.js -o ./build/js/app.js --mode=development
复制代码- 功能: webpack能够打包js和json文件,并且能将es6的模块化语法转换成浏览器能识别的语法
打包指令(生产):
1
2webpack ./src/js/app.js -o ./build/js/app.js --mode=production
复制代码- 功能: 在开发配置功能上加上一个压缩代码的功能
index.html页面中引入:build/js/app.js
结论:
- webpack能够编译打包js和json文件
- 能将es6的模块化语法转换成浏览器能识别的语法
- 能压缩代码
缺点:
- 不能编译打包css、img等文件
- 不能将js的es6基本语法转化为es5以下语法
改善:使用webpack配置文件解决,自定义功能
4. webpack配置文件
- 目的:在项目根目录定义配置文件,通过自定义配置文件,还原以上功能
- 文件名称:webpack.config.js
- 文件内容:
1 | const { resolve } = require('path'); //node内置核心模块,用来设置路径。 |
- 运行指令: webpack
5. 打包less、css资源
概述:less、css文件webpack不能解析,需要借助loader编译解析
创建less文件
- src/css/demo1.less
- src/css/demo2.css
入口app.js文件
- 引入less、css资源
安装loader
- npm install css-loader style-loader less-loader less -D
配置loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18{
// 处理less资源
test: /\.less$/,
use: [
'style-loader', //创建style标签,将js中的样式资源插入进行,添加到head中生效
'css-loader', //将css文件变成commonjs模块加载js中,里面内容是样式字符串
'less-loader' //将less文件编译成css文件
]
},
{
// 处理css资源
test: /\.css$/,
use: [ // use数组中loader执行顺序:从右到左,从下到上 依次执行
'style-loader',// 创建style标签,将js中的样式资源插入进行,添加到head中生效
'css-loader'// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
]
},
复制代码运行指令:webpack
6. 打包html文件
概述:借助html-webpack-plugin插件打包html资源
创建html文件
- src/index.html
- 注意:不要在该html中引入任何css和js文件
安装插件:html-webpack-plugin
- npm install html-webpack-plugin -D
在webpack.config.js中引入插件(插件都需要手动引入,而loader会自动加载)
- const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
配置插件Plugins
1
2
3
4
5
6
7plugins: [
new HtmlWebpackPlugin({
// 以当前文件为模板创建新的HtML(1. 结构和原来一样 2. 会自动引入打包的资源)
template: './src/index.html',
}),
]
复制代码运行指令:webpack
7. 打包样式中的图片
概述:图片文件webpack不能解析,需要借助loader编译解析
添加2张图片:
- 小图, 小于8kb: src/images/vue.png
- 大图, 大于8kb: src/images/react.jpg
在less文件中通过背景图的方式引入两个图片
安装loader
- npm install file-loader url-loader file-loader -D
- 补充:url-loader是对象file-loader的上层封装,使用时需配合file-loader使用。
配置loader
1
2
3
4
5
6
7
8
9
10
11{
// 处理图片资源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader', //url-loader是对file-loader的上层封装
options: {
limit: 8 * 1024, //临界值为8KB,小于8KB的图片会被转为base64编码
name: '[hash:10].[ext]', //加工后图片的名字
outputPath: 'imgs' //输出路径
}
},
复制代码
8. 打包html中的图片
概述:html中的
<img>标签url-loader没法处理,需要引入其他loader处理。添加图片
- 在src/index.html添加一个img标签,src/images/angular.png
安装loader
- npm install html-loader –save-dev
配置loader
1
2
3
4
5
6{
// 处理html中<img>资源
test: /\.html$/,
loader: 'html-loader'
},
复制代码可能出现的坑:打包后html文件中的图片的src变成了:[object Module],
解决办法:url-loader中加入一个配置:esModule:false即可
9. 打包其他资源
概述:其他资源(字体、音视频等)webpack不能解析,需要借助loader编译解析
以处理几个字体图标的字体为例,font下添加几个下载好的字体文件:
- src/font/iconfont.eot
- src/font/iconfont.svg
- src/font/iconfont.ttf
- src/font/iconfont.woff
- src/font/iconfont.woff2
修改incofont.css中字体的url
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18@font-face {
font-family: 'iconfont';
src: url('../media/iconfont.eot');
src: url('../media/iconfont.eot?#iefix') format('embedded-opentype'),
url('../media/iconfont.woff2') format('woff2'),
url('../media/iconfont.woff') format('woff'),
url('../media/iconfont.ttf') format('truetype'),
url('../media/iconfont.svg#iconfont') format('svg');
}
.iconfont {
font-family: "iconfont" ;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
复制代码修改html,添加字体图标,例如:
<span class="iconfont icon-icon-test"></span>配置loader
1
2
3
4
5
6
7
8
9
10{
// 处理其他资源(字体、音视频等等)
exclude: /\.(html|js|css|less|jpg|png|gif)/, //排除的文件
loader: 'file-loader',
options: {
name: '[hash:10].[ext]', //命名
outputPath: 'media' //输出路径
}
}
复制代码运行指令:webpack
10. devServer
安装webpack-dev-server
- npm i webpack-dev-server -D
- npm i webpack-dev-server -g
- 详细配置见官网:指南 -> 开发环境 -> 使用webpack-dev-server
修改webpack配置对象,追加devServer配置(注意不是loader中追加)
1
2
3
4
5
6
7//devServer配置(开发模式所特有的配置)
devServer: {
contentBase: resolve(__dirname, 'build'),//本地打包文件的位置
port: 3000, //端口号
open: true //自动打开浏览器
}
复制代码修改package.json中scripts指令
"dev": "webpack-dev-server",
运行指令:npm run dev 或者 yarn dev
至此,你已经完成了用webpack搭建一个简单的开发环境,但这套配置只适用于开发过程中调试代码,项目上线并不能运用这套配置,因为你还有很多的问题没有处理,比如:css还不是单独的文件,css、js还有很多兼容性问题等等,接下来我们开始去搭建生产环境。
生产环境准备:
1.新建config文件夹,重命名webpack.config.js为webpack.dev.js,放入config文件夹 2.复制webpack.dev.js,重命名为webpack.prod.js,删除其中的devServer配置,因为这是开发环境特有的,生产环境是不需要的 3.修改package.json中scripts指令:
1 | "start": "webpack-dev-server --config ./config/webpack.dev.js", |
4.修改output中path为:path: resolve(__dirname, '../build')
1. 提取css为单独文件
安装插件
- npm install mini-css-extract-plugin -D
引入插件
- const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);
配置loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20//引入mini-css-extract-plugin,用于提取css为单独文件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
{
// 处理less资源
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader',
]
},
{
// 处理css资源
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
]
}
复制代码配置插件
1
2
3
4
5
6//提取css为单独文件
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: 'css/built.css',
})
复制代码运行指令
- npm run build
备注:由于在提取了独立的文件,要从外部引入,所以可能会有路径问题,解决方案是在output配置中,添加:
publicPath:'/'publicPath根据实际情况自行调整,若上线运行值为:/imgs,若本地右键运行值为:/build/imgs
2. css兼容性处理
- 安装loader
- npm install postcss postcss-loader postcss-preset-env -D
- 因为css和less样式文件都要进行兼容性处理,所以我们定义好一个通用的配置:
1 | // 配置一个commonCssLoader,处理less和css时都会使用 |
- 修改css-loader和less-loader配置
1 | { |
配置package.json,在其中追加browserslist配置,通过配置加载指定的css兼容性样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16"browserslist": {
// 开发环境
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认是生产环境
"production": [
">0.2%", //兼容市面上99.8%的浏览器
"not dead", //"死去"的浏览器不做兼容,例如IE8
"not op_mini all",//不做opera浏览器mini版的兼容
"ie 10" //兼容IE10
]
}
复制代码备注1: browserslist 是一套描述产品目标运行环境的工具,它被广泛用在各种涉及浏览器/移动端的兼容性支持工具中,详细配置规则参考:github.com/browserslis…
备注2:若出现版本不兼容,或配置不正确的错误,那么需更换依赖包版本:
1
2npm i less-loader@5 postcss-loader@3
复制代码运行指令:
- npm run build
3. js语法检查
概述:对js基本语法错误/隐患,进行提前检查
安装loader
- npm install eslint-loader eslint -D
安装检查规则库:
- npm install eslint-config-airbnb-base eslint-plugin-import -D
备注:eslint-config-airbnb-base定制了一套标准的、常用的js语法检查规则,推荐使用
配置loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16module: {
rules: [
{
// 对js进行语法检查
test: /\.js$/,
exclude: /node_modules/,//排除这个文件
// 优先执行
enforce: 'pre',//优先执行 只要webpack启动时 尽可能先执行 可不写
loader: 'eslint-loader',
options: {
fix: true //若有问题自动修复,重要!!!!
}
}
]
}
复制代码修改package.json 库的底层实现
1
2
3
4
5
6
7"eslintConfig": {
"extends": "airbnb-base", //直接使用airbnb-base提供的规则 需要下载的
"env": {
"browser": true//如果运行环境不是浏览器 则运行环境为node 此时需要将这个改为false
}
}
复制代码运行指令:webpack
备注:若出现:warning Unexpected console statement no-console警告,意思是不应该在项目中写console.log(),若想忽略,就在要忽略检查代码的上方输入一行注释:// eslint-disable-next-line即可。
黄色的警告证明打印了log 可在上面加eslint-disable-next-line 也可以不管它
4. js语法转换
概述:将浏览器不能识别的新语法转换成原来识别的旧语法,做浏览器兼容性处理
安装loader
- webpack4版本以上可直接安装 3版本的还需定义@后面的版本 借鉴官网
- npm install babel-loader @babel/core @babel/preset-env -D
配置loader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
复制代码运行指令:webpack
5. js兼容性处理
安装包
npm install @babel/polyfill
琳-用于高级兼容 可以解决babel中无法解决的 大项目没有不用的 记住 可以解决ie中不认识promise
在app.js中引入
使用
1
2
3- app.js
import '@babel/polyfill'; // 包含ES6的高级语法的转换
复制代码
6. 压缩html、压缩js
- 直接修改webpack.prod.js中的model为production即可。
- 备注:若设置了模式为production,必须在new HtmlWebpackPlugin时添加配置minify: false:
1 | new HtmlWebpackPlugin({ |
7.压缩css
webpack 4.0版本以上可以自动压缩html js 不能压缩css optimize优化 assets静态资源
安装插件
1
2npm install optimize-css-assets-webpack-plugin -D
复制代码引入插件
1
2const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
复制代码配置插件
1
2
3
4
5
6new OptimizeCssAssetsPlugin({
cssProcessorPluginOptions: {
preset: ['default', { discardComments: { removeAll: true } }],//移出所有注释
},
})
复制代码以上就是webpack生产环境的配置,可以生成打包后的文件。
总结
1.webpack配置文件
1 | module.exports = { |
2.webpack打包的基本流程
- 连接: webpack从入口JS开始,递归查找出所有相关的模块, 并【连接】起来形成一个图(网)的结构
- 编译: 将JS模块中的模块化语法【编译】为浏览器可以直接运行的模块语法(当然其它类型资源也会处理)
- 合并: 将图中所有编译过的模块【合并】成一个或少量的几个文件, 浏览器真正运行是打包后的文件
3.比较loader与plugins
- loader: 用于加载特定类型的资源文件, webpack本身只能打包js和json。
- plugin: 用来扩展webpack其它方面的功能, 一般loader处理不了的资源、完成不了的操作交给插件处理。
4.live-reload(自动刷新)与HMR(热模替换)
- 相同点: 代码修改后都会自动重新编译打包
- 不同点: live-reload: 刷新整体页面, 从而查看到最新代码的效果, 页面状态全部都是新的。 HMR: 没有刷新整个页面, 只是加载了修改模块的打包文件并运行, 从而更新页面的局部界面, 整个界面的其它部分的状态还在
5.webpack常用loader与plugin汇总
常用loader:
1 | 1.【less-loader】用于将less文件翻译成为css |
常用pulgins:
1 | 1.【mini-css-extract-plugin】:用于提取项目中的css为一个单独的文件。 |
6. webpack中的tree-shaking
- 概述:有些时候,我们一个模块向外暴露了n个函数、对象、或其他一些数据,但是我们只是用到了其中的一个或几个,那在最终打包的时候,我们只希望把我们所用的打包进去,这时候就要tree-shaking,即:去除无用代码。
- 配置:同时满足两个条件webpack会自动开启tree-shaking
1 | 1. 使用ES6模块化 |
- webpack打包原理:
webpack将一切文件视为模块,通过定义entry.js对所有的依赖文件进行跟踪,将各个模块通过loader和plugins处理,然后打包在一起。
- loader 和 plugin 区别是什么?
loader是模块转换器,因为webpack只支持对js文件的打包,如果需要进行css、html等文件的打包需要使用相对应的loader,针对的是一个单纯的文件。
plugin是插件,是用于增强webpack功能尚未,针对的是webpack打包的整个过程,比如使用插件将css提取到一个单独的文件中(miini-css-extract-plugin)
- 常用loader与插件(需要使用require引入)及其使用:
开发环境下:
打包css文件:style-loader、css-loader
打包less文件:style-loader、css-loader、less-loader、less
打包html文件:引入Html-Webpack-Plugin插件,然后在plugins中进行配置,使用template声明复制的html文件
打包jpg/png/gif文件:url-loader,可以在options中配置,limit:图片小于指定大小使用base64处理,esModule指定是否使用es6模块化,name给图片重命名
打包html中的图片:html-loader
打包其他资源:file-loader
生产环境:
提取css为单独文件:使用mini-css-extract-plugin插件,然后在plugins中进行配置,可以对输出的css文件重命名,然后使用MiniCssExtractPlugin.loader取代style-loader
css兼容性处理:postcss-loader、postcss-preset-env
1 | //配置loader |
压缩CSS:optimize-css-assets-webpack-plugin,直接在plugins中新建一个对象即可
js语法检查:eslint-loader、eslint、eslint-config-airbnb-base、eslint-plugin-import
1 | //在loader中配置 |
js兼容性处理:babel-loader、@babel/core、@babel/preset-env、@babel/ployfill、core-js
1 | //在loader中配置 |
js压缩:生产环境下默认压缩代码
html压缩:在Html-Webpack-Plugin中进行配置
1 | //在插件中进行配置 |
- 性能优化:
开发环境:
HMR:模块热替换,当一个模块发生变化只会重新打包这个模块,无需重新加载整个页面,将dev-serve配置中hot属性更改为true即可。HMR模块对js的处理只能处理非入口js文件的其他文件;html文件默认不能使用HMR功能。
source-map:一种可以提供源代码到构建后的代码映射的技术,有了它以后除错工具可以显示原始代码错误,而不是转换后的代码,在配置文件webpack.config.js中添加键值对:devtool:”eval-source-map”,有多个选项可以根据开发环境或生产环境进行选择。
oneOf:正常来说一个文件一般只需要被一个loader处理,但是在打包过程中全部loader都会匹配一次,可以在rules中声明的oneOf数组可以用来表示不能有两个配置处理同一类型的文件。
缓存:
- babel缓存:在babel-loader配置添加cacheDirectory:true;
- 文件资源缓存:在输出文件命名中添加hash值,使用contenthash可以根据文件的内容hash最好的使用缓存,webpack产生的hash与chunkhash都存在弊端。
tree-shaking:去除无用代码,没有用到的不会被打包,减少文件体积。前提需要使用es6模块化和开启生产环境,然后在package.json中配置“sideEffects”:”false”,这样所有的代码都会被tree-shaking,可以使用”sideEffects”:[“*.css*“]在数组中声明不需要tree-shaking的文件。
代码分割:
1、在entry配置多个入口文件,最终就会输出多个bundle
2、在webpack.config.js中进行如下配置,可以将node-modules中代码单独打包成一个chunk输出,还可以分析多入口的chunk中,如果一个文件被重复使用,也会打包成一个chunk
1 | optimization: { |
懒加载:在引入文件的时候使用一下配置实现懒加载,webpackChunkName指定chunk的命名,webpackPrefetch指定是否使用预加载
1 | document.getElementById('btn').onclick = function() { |
PWA:渐进式网络开发框架(离线可访问),需要下载workbox-webpack-plugin然后在plugins进行配置:
1 | //webpack.config.js |
多进程打包:开启多进程打包可以使用thread-loader,但是由于进程启动需要600ms,而且进程通信也有开销,所以只有在js文件多且大的情况下才需要多进程打包。
1 | test: /\.js$/, |
externals:在webpack.config.js中声明,指定哪些文件不需要进行打包,而是使用外部CDN资源加载
DDL:把第三方代码完全分离开,每次只打包自身的代码,第三方代码只需要打包一次就行。首先先配置webpck.dll.js,如下;然后再在webpack.config.js中进行配置,如下:
1 | //webpack.config.js |
- 如何提高webpack打包速度:
优化loader:
对babel-loader的文件搜索范围进行优化,配置include以及exclude属性声明在哪里查找js文件以及不去查找的路径,通过cacheDirectory属性对babel文件进行缓存。
HappyPack:将loader的同步执行转换为并行的,使用HappyPack插件。也可以使用官方推荐的thread-loader,
DDLPlugin:将特定的类库提前打包然后引入,这样以后每次打包只会在类库有更新才需要重新打包。
代码压缩:将环境改为生产环境即可
。。。
- 如何减少webpack打包体积:
按需加载:在开发单页面应用时对一些路由页面使用按需加载,他们会被单独打包成一个文件,使用import异步引入的方式。
Scope Hoisting:分析模块之间的依赖关系,尽可能把打包的模块合并到一个函数中去,只需要在optimization里面配置concatenateModules为true即可。
tree-shaking:删除项目中没有被引用的代码,开启生产环境就会自动启用这个功能。如果不希望css文件执行tree-shaking,可以在package.json中对”sideEffects”:[“*.css*“]进行配置。
- bundle、chunk、module是什么:
bundle:是由webpack打包出来的文件
chunk:代码块,一个chunk由多个模块组成,用于代码的合并和分割
module:是开发中的单个模块,在webpack中一切皆模块,一个模块对应一个文件,webpack会从入口文件递归开始找出所有依赖的模块
- webpack构建流程:
webpack的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
1、初始化参数:从配置文件和shell语句中读取与合并参数,得出最终的参数
2、开始编译:用上一次得到的参数初始化compiler对象,加载所有配置的插件,执行对象的run方法开始执行编译
3、确定入口:根据配置中的entry找出所有的入口文件
4、编译模块:从入口文件出发,调用所以配置的loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有的入口文件依赖的文件都经过本步骤的处理
5、完成模块编译:在经过第四步使用loader翻译完所以模块后,得到每个模块被翻译后的最终内容以及他们之间的依赖关系
6、输出资源:根据入口与模块之间的依赖关系,组装成一个个包含多个模块的chunk,再把每个chunk转换为一个单独的文件加入到输出列表。
7、输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用webpack提供的API改变webpack运行结果。