webpack 其实就是一个 JavaScript 应用程序的静态模块打包器。
webpack 有什么作用?
模块化打包:webpack 会将项目的资源文件当成一个一个模块,模块之间会有依赖关系。webpack 将会对这些有依赖关系的文件进行处理,让浏览器能够识别,最后将应用程序需要的每个模块打包成一个或者多个 bundle。
官方中文文档:https://www.webpackjs.com/concepts/
1. 讲解 webpack 开发环境的搭建,打包模式和效果
1)安装 node
node 官网地址:https://nodejs.org/zh-cn/
安装完后,可以通过命令行输入:node -v 查看 node 版本信息
通过命令行输入:npm -v 查看 npm 版本信息
2)创建 package.json 文件
进入到项目的根目录,输入命令:npm init,一系列的提示,如果不需要直接回车
最终会在根目录下生成 package.json 文件
3)安装webpack
本地安装:(推荐)
npm install --save-dev webpack
npm install --save-dev webpack-cli
全局安装:
npm install --global webpack webpack-cli
这里我选择本地安装,还是进入到项目根目录,输入命令:npm install webpack webpack-cli --save-dev
4)打包
默认 entry 入口 src/index.js
默认 output 出口 dist/main.js
入口和出口都是可以设置的,后面会讲,这里先演示效果,在项目中新建目录和文件
webpack有两种打包模式:webpack --mode development 和 webpack --mode production
我们先设置好这两个打包命令
设置好后在命令行程序中运行 npm run dev 或者 npm run prod 来进行打包。
webpack --mode development 打包模式下的打包效果如下图所示:
webpack --mode production 打包模式下的打包效果如下图所示:
2. webpack 核心配置 config 文件的初使用
1)新建一个 webpack.config.js
2)配置入口 entry(所需打包的文件路径)
3)配置出口 output
(1)path 指文件打包后的存放路径
(2)path.resolve() 方法将路径或路径片段的序列处理成绝对路径
(3)__dirname 表示当前文件所在的目录的绝对路径
(4)filename 是打包后文件的名称
命令行程序运行 npm run dev 或者 npm run prod
const path = require('path'); module.exports = { entry:'./public/index.js', output:{ path:path.resolve(__dirname,'build'), filename:'build.js' } }
3. 讲解入口和出口的多文件用法
入口 entry
单入口
单文件
例如: entry:'./src/index.js'
多文件
在你想要多个依赖文件一起注入,并且将它们的依赖导向到一个“chunk”时,传入数组的方式就很有用。
例如:entry:['./src/index.js','./src/index2.js',...]
多入口
例如:
entry:{
pageOne:'./src/pageOne/index.js',
pageTwo:'./src/pageTwo/index.js',
pageThree:'./src/pageThree/index.js'
}
出口 output
单出口
output:{
path:path.resolve(__dirname,'build'),
filename:'build.js'
}
多出口(需要和多入口搭配使用)
output:{
path:path.resolve(__dirname,'build'),
filename:'[name].js'
}
4. 讲解 webpack 如何配置本地服务器
webpack-dev-server 是 webpack 官方提供的一个小型 Express 服务器。使用它可以为 webpack 打包生成的资源文件提供 web 服务。
webpack-dev-server 主要提供两个功能:
(1)为静态文件提供服务
(2)自动刷新和热替换(HMR)
1)安装 webpack-dev-server
npm install --save-dev webpack-dev-server
2)配置 webpack.config.js 文件
const path = require('path'); module.exports = { entry:'./public/index.js', output:{ path:path.resolve(__dirname,'build'), filename:'build.js' }, devServer:{ contentBase:'./build', //设置服务器访问的基本目录 host:'localhost', //服务器的ip地址 port:'8080', //端口 open:true //自动打开页面 } }
3)配置 package.json
"start": "webpack-dev-server --mode development"
4)在 build 文件夹下新建 index.html 文件,在 html 中引入 bundle.js
5)在命令行程序运行 npm run start
6)自动弹出页面,控制台有输出信息
5. 讲解 css 加载器的使用方式
1)了解 loader
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
2)安装loader
安装 style-loader 和 css-loader
下载:npm install style-loader css-loader --save-dev
3)配置 loader
在 webpack.config.js 文件里配置 module 中的 rules
在 webpack 的配置中 loader 有两个目标:
test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
use 属性,表示进行转换时,应该使用哪个 loader。
代码:
module:{ rules:[ { test:/.css$/, use:['style-loader','css-loader'] } ] }
4)创建 index.css 文件并 import 进 index.js 文件中
6. 讲解 webpack 编译 less 和 sass 的方式
安装 less-loader 和 less
下载:npm install less-loader less --save-dev
安装 sass-loader 和 node-sass
下载:npm install sass-loader node-sass --save-dev
配置和上面一样,使用对应的 loader 就可以了
7. 使用 PostCSS 自动添加 css3 浏览器前缀
处理效果
编译为
1)安装 postcss-loader 和 autoprefixer
下载:npm install postcss-loader autoprefixer --save-dev
2)配置 loader(需要和 autoprefixer 一起用)
const path = require('path'); module.exports = { entry:'./public/index.js', output:{ path:path.resolve(__dirname,'build'), filename:'build.js' }, devServer:{ contentBase:'./build', //设置服务器访问的基本目录 host:'localhost', //服务器的ip地址 port:'8080', //端口 open:true //自动打开页面 }, module:{ rules:[ { test:/.css$/, use:['style-loader','css-loader',{ loader:'postcss-loader', options:{ plugins:[ require("autoprefixer")({ overrideBrowserslist: [ 'ie >= 8',//ie版本大于等于ie8 'Firefox >= 20',//火狐浏览器大于20版本 'Safari >= 5',//safari大于5版本 'Android >= 4',//版本大于Android4 'Ios >= 6',//版本大于ios6 'last 4 version'//浏览器最新的四个版本 ] }) ] } }] } ] } }
在低版本中可以使用 browsers,如果报了这样的错误,就需要使用 overrideBrowserslist 替换掉 browsers 就可以了。
或者在 package.json 里加上设置:
{ "name": "webpackdemo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack --mode development", "prod": "webpack --mode production", "start": "webpack-dev-server --mode development" }, "author": "jwen", "license": "ISC", "devDependencies": { "autoprefixer": "^9.7.2", "css-loader": "^3.2.0", "less": "^3.10.3", "less-loader": "^5.0.0", "postcss-loader": "^3.0.0", "style-loader": "^1.0.0", "webpack": "^4.41.2", "webpack-cli": "^3.3.10", "webpack-dev-server": "^3.9.0" }, "browserslist": [ "ie >= 8", "Firefox >= 20", "Safari >= 5", "Android >= 4", "Ios >= 6", "last 4 version" ] }
这样一来 webpack.config.js 就不需要设置了
8.讲解使用 file-loader 处理图片加载
1)下载安装 file-loader
npm install file-loader --save-dev
2)配置config文件
选项配置
配置options:
name:为你的文件配置自定义文件名模板(默认值[hash].[ext])
context:配置自定义文件的上下文,默认为 webpack.config.js
publicPath:为你的文件配置自定义 public 发布目录
outputPath:为你的文件配置自定义 output 输出目录
[ext]:资源扩展名
[name]:资源的基本名称
[path]:资源相对于 context的路径
[hash]:内容的哈希值
9.讲解使用 file-loader 处理字体文件
1)下载字体文件,以 bootstrap 字体文件为例子
Boostrap字体文件下载地址:https://v3.bootcss.com/getting-started/
2)在 index.js 中引入bootstrap.css,在 html 中使用 bootstrap 字体图标
配置config文件
{ test:/.(eot|svg|ttf|woff|woff2)$/, use:[{ loader:'file-loader', options:{ outputPath:'./fonts' } }] }
10.讲解使用 file-loader 处理第三方js库
以 jquery 库为例子
第一种方法:
1)本地导入
2)编写配置文件:
webpack.ProvidePlugin 参数是键值对形式,键就是我们项目中使用的变量名,值就是键所指向的库。webpack.ProvidePlugin 会先从 npm 安装的包中查找是否有符合的库。
如果 webpack 配置了 resolve.alias 选项(理解成“别名”),那么 webpack.ProvidePlugin 就会顺着设置的路径一直找下去
使用 webpack.ProvidePlugin 前需要引入 webpack
const path = require('path'); const webpack = require('webpack'); module.exports = { entry:'./public/index.js', output:{ path:path.resolve(__dirname,'build'), filename:'build.js' }, devServer:{ contentBase:'./build', //设置服务器访问的基本目录 host:'localhost', //服务器的ip地址 port:'8080', //端口 open:true //自动打开页面 }, module:{ rules:[ { test:/.css$/, use:['style-loader','css-loader',{ loader:'postcss-loader', options:{ plugins:[ require("autoprefixer") ] } }] }, { test:/.(eot|svg|ttf|woff|woff2)$/, use:[{ loader:'file-loader', options:{ outputPath:'./fonts' } }] } ] }, resolve:{ alias:{ jQuery:path.resolve(__dirname,'public/js/jquery.js') } }, plugins:[ new webpack.ProvidePlugin({ jQuery: 'jQuery'//绿色的表示js中使用的变量名,这个可以随便起,比如这里起名:haha,那么在下面的截图中就可以使用haha }) ] }
第二种方法:
1)npm 安装 jquery 库:npm install jquery --save-dev
2)直接在 js 里 import 引入:import $ from 'jquery'
11. 使用 babel-loader 编译 ES6 语法
目前,ES6(ES2015)这样的语法已经得到很大规模的应用,它具有更加简洁、功能更加强大的特点,实际项目中很可能会使用采用了ES6语法的模块,但浏览器对于ES6语法的支持并不完善。为了实现兼容,就需要使用转换工具对ES6语法转换为ES5语法,babel就是最常用的一个工具
babel 转化语法所需依赖项:
babel-loader: 负责 es6 语法转化
babel-core: babel 核心包
babel-preset-env:告诉 babel 使用哪种转码规则进行文件处理
1)安装依赖:npm install babel-loader @babel/core @babel/preset-env --save-dev
2)配置config文件
{ test:/.js$/, exclude:/node_modules/, use:'babel-loader' }
exclude表示不在指定目录查找相关文件
3)根目录新建 .babelrc 文件配置转换规则
{ "presets":["@babel/preset-env"] }
另一种规则配置(不需要建 .babelrc 文件,直接在 webpack.config.js 里配置)
{ test:/.js$/, exclude:/node_modules/, use:{ loader:'babel-loader', options:{ presets:["@babel/preset-env"] } } }
12. 讲解如何使用插件根据模板自动生成html文件并关联相关文件
HtmlWebpackPlugin 会自动为你生成一个 HTML 文件,根据指定的 index.html 模板生成对应的 html 文件。
1)安装依赖:npm install html-webpack-plugin --save-dev
2)配置 config 文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins:[ new HtmlWebpackPlugin({ template:'./public/index.html', filename:'webpack.html', minify:{ minimize:true, removeAttributeQuotes:true, removeComments:true, minifyCSS:true, minifyJS:true, removeEmptyElements:true, collapseWhitespace:true }, hash:true }) ]
13. 讲解如何从打包后的chunk文件中提取分离出css
将所有的入口 chunk(entry chunks)中引用的 css,移动到独立分离的 CSS 文件
方法一:使用 ExtractTextPlugin 插件
1)下载插件:npm install --save-dev extract-text-webpack-plugin@next
2)配置config文件
const ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports = { module: { rules: [ { test: /.css$/, use: ExtractTextPlugin.extract({ fallback: "style-loader", use: "css-loader" }) } ] }, plugins: [ new ExtractTextPlugin("./css/styles.css"), ] }
方法二:使用 mini-css-extract-plugin 插件
1)下载插件:npm install --save-dev mini-css-extract-plugin
2)配置 config 文件
const MiniCssPlugin = require("mini-css-extract-plugin"); module.exports = { module: { rules: [ { test: /.css$/, use: [MiniCssPlugin.loader,'css-loader'] } ] }, plugins: [ new MiniCssPlugin({ filename:'./css/styles.css' }) ] }
14. 讲解使用插件压缩css及优化css结构
1)下载插件:npm install --save-dev optimize-css-assets-webpack-plugin
2)配置 config 文件
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); module.exports = { plugins: [ new OptimizeCssAssetsPlugin({ assetNameRegExp:/.css$/g, cssProcessor:require("cssnano"), cssProcessorPluginOptions:{ preset:['default',{discardComments:{removeAll:true}}] }, canPrint:true }) ] }
assetNameRegExp:正则表达式,用于匹配需要优化或者压缩的资源名。默认值是 /.css$/g
cssProcessor:用于压缩和优化CSS 的处理器,默认是 cssnano.
cssProcessorPluginOptions:传递给cssProcessor的插件选项,默认为{}
canPrint:表示插件能够在console中打印信息,默认值是true
discardComments:去除注释
15. 讲解如何拷贝静态资源文件到打包后的目录
1)下载插件:npm install --save-dev copy-webpack-plugin
2)配置 config 文件
const CopyWebpackPlugin = require("copy-webpack-plugin"); module.exports = { plugins: [ new CopyWebpackPlugin([ { from:__dirname+'/public/assets', to:__dirname+'/build/assets' } ]) ] }
16. 讲解如何清除之前打包的旧文件
当我们修改带hash的文件并进行打包时,每打包一次就会生成一个新的文件,而旧的文件并没有删除。为了解决这种情况,我们可以使用clean-webpack-plugin在打包之前将文件先清除,之后再打包出最新的文件
1)下载插件:npm install --save-dev clean-webpack-plugin
2)配置 config 文件
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); module.exports = { plugins: [ new CleanWebpackPlugin() ] }
插件地址:https://www.npmjs.com/package/clean-webpack-plugin
17. 讲解 webpack 如何处理 html 中引入的图片
未使用 loader 时,会出现路径错误,图片不显示的情况
1)下载 loader:npm install --save-dev html-loader
2)配置 config 文件
{ test: /.(png|jpg|jpeg|gif)$/, use: 'file-loader' }, { test: /.html$/, use: { loader: 'html-loader', options: { minimize: true } } }
18. 讲解 sourcemap 的作用和调试方式
sourcemap 是为了解决实际运行代码(打包后的)出现问题时无法定位到开发环境中的源代码的问题。
对于 js 调试来说,只需要设置 devtool,对于 css 调试,需要设置 css-loader 的可选项。
19. webpack 开发调试必备功能之模块热替换 HMR
模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。主要是通过以下几种方式,来显著加快开发速度:
- 保留在完全重新加载页面时丢失的应用程序状态。
- 只更新变更内容,以节省宝贵的开发时间。
- 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。
配置config文件
Plugin设置
NamedModulesPlugin:当开启 HMR 的时候使用该插件会显示模块的相对路径
其他配置
devServer中加入hotOnly表示只有热更新,不会自动刷新页面
修改js文件时代码不会自动热更新,需加入以下代码可以告诉 webpack 接受更新的模块
20. 讲解如何区分生产环境和开发环境的配置
开发环境和生产环境的构建目标差异很大。在开发环境中,我们需要具有强大的、具有实时重新加载或热模块替换能力和 localhost server。 而在生产环境中,我们的目标则转向于关注更小的 bundle,以及资源的优化,以改善加载时间。所以我们通常建议为每个环境编写彼此独立的 webpack 配置。
1)安装插件:npm install --save-dev webpack-merge
2)拆分文件
在这里我们可以将 webpack.config.js 拆分为三个文件,分别是 webpack.common.conf.js、webpack.dev.conf.js 和 webpack.prod.conf.js。
webpack.common.conf.js 是放一些我们公用的配置,比如入口entry、出口output、常用loader以及插件等。
webpack.dev.conf.js 是在开发环境上的配置,比如devServer配置、模块热替换等方便开发的配置
webpack.prod.conf.js 是在生产环境上的配置,比如提取分离css、压缩css和js等
webpack.common.conf.js
webpack.dev.conf.js
webpack.prod.conf.js
3)修改 package.json 文件中的script
--config可以指定使用的配置文件