什么是 webpack

webpack是一个模块打包工具,它会从入口文件开始,分析各个模块之间的依赖关系,并使用 loader 处理那些非js文件的模块,最终打包生成能够供浏览器使用的文件。

Webpack基础 - 图1

安装

建议局部安装,不同项目 webpack 版本可能不一样

  1. # 查看webpack历史发布信息
  2. npm info webpack
  3. # 局部安装
  4. npm install webpack webpack-cli -D
  5. # 安装指定版本
  6. npm install webpack@x.xx webpack-cli -D
  7. # 检查安装是否成功,npx 帮助我们在项⽬中的 node_modules ⾥查找 webpack
  8. npx webpack -v || ./node_modules/.bin/webpack -v

webpack核心概念

webpack 默认的配置文件名称为 webpack.config.js,可通过 — config 选项指定自定义的名称。

  1. npx webpack --config webpack.dev.config.js

webpack默认的入口文件为 src/index.js,输出文件为 dist/main.js。
webpack默认的配置比较弱,大部分的功能需要通过自定义配置实现。

entry

指定 webpack 打包入口文件,入口分为单入口多入口,webpack 执行构建的第一步将从entry开始。

  1. // 单入口
  2. entry: "./src/index.js",
  3. // 单入口也可以使用对象语法
  4. entry: {
  5. index: "./src/index.js"
  6. },
  7. // index、login是 chunkName,可自定义
  8. entry: {
  9. index: "./src/index.js",
  10. login: "./src/login.js"
  11. }

output

webpack 打包后的输出结果

  1. // 单入口的处理
  2. output: {
  3. filename: "bundle.js", // 输出⽂件的名称,默认为 main.js
  4. path: path.resolve(__dirname, "dist"), // 输出⽂件到磁盘的⽬录,必须是绝对路径
  5. publicPath: '/' // 资源基础路径,index.html 中加载的资源都会以这个路径为基础
  6. }
  7. // 多⼊⼝的处理
  8. output: {
  9. filename: "[name][chunkhash:8].js", // 利⽤占位符,指定输出的文件名称为入口处的 chunkName
  10. path: path.resolve(__dirname, "dist") // 输出⽂件到磁盘的⽬录,必须是绝对路径
  11. }

hash:每次打包构建时都会改变 chunkhash:入口文件对应的 chunk 改变,chunkhash 才会发生改变 contenthash:文件内容发生变化,contenthash 才会改变

mode

指定当前构建环境,用于 webpack 内部优化

Webpack基础 - 图2

loader

webpack 默认只知道处理 js 和 json 文件。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效的模块。
当 webpack 处理到不认识的模块时,需要在 module.rules 中进行配置,使用相应的 loader 来处理:

  1. module: {
  2. rules: [
  3. {
  4. test: /\.(png|jpe?g|gif)$/,
  5. // use: "url-loader",
  6. use: {
  7. loader: "url-loader",
  8. // 额外的配置
  9. options: {
  10. name: "[name].[ext]", // name、ext: 未打包的资源模块的名称和后缀
  11. outputPath: "images/", // 打包后文件放置的位置
  12. limit: 2048
  13. }
  14. }
  15. },
  16. {
  17. test: /\.(woff2|woff)$/,
  18. use: {
  19. loader: "file-loader"
  20. }
  21. },
  22. {
  23. test: /\.less$/,
  24. use: [
  25. MiniCssExtractPlugin.loader,
  26. "css-loader",
  27. "less-loader",
  28. "postcss-loader"
  29. ]
  30. }
  31. ]
  32. }

file-loader、url-loader

file-loader 用来处理静态资源模块,它会把需要处理的模块,从源代码移动到打包目录。
url-loader 内部使⽤了 file-loader,所以可以处理 file-loader处理的所有的事情,不同的是url-loader 可以通过 limit 属性对图片分情况处理,当图片小于 limit(单位:byte)大小时转为 base64 格式,大于 limit 时调用 file-loader 对图片进行处理。

style、css、less loader

style-loader 会把 css-loader ⽣成的内容,放入 style 中挂载到⻚⾯的 head 部分
css-loader 分析css模块之间的关系,并合成⼀个css
less-load 把 less 语法转换成 css

loader 的加载顺序:从右到左,从下到上 详细:CSS loader配置解读

postcss-loader autoprefixer

PostCss是一个样式处理工具,它通过自定义的插件来重新定义css。它鼓励开发者使用规范的css原生语法编写代码,然后配置编译器转换需要兼容的浏览器版本,最后通过编译将源码转换为目标浏览器可用的css代码。

postCss 插件:https://github.com/postcss/postcss/blob/master/docs/plugins.md

postcss-loader autoprefixer 配合使用,用于样式自动添加前缀

  1. {
  2. test: /\.less$/,
  3. use: [
  4. "style-loader",
  5. "css-loader",
  6. "less-loader",
  7. {
  8. loader: "postcss-loader",
  9. options: {
  10. plugins: () => [
  11. require("autoprefixer")({
  12. // autoprefixer 新版本中 browsers 替换成 overrideBrowserslist
  13. overrideBrowserslist: ["last 2 versions",">1%"]
  14. })]
  15. }
  16. }
  17. ]
  18. }

可以将 autoprefixer 的配置抽离到 postcss.config.js 中

  1. module.exports = {
  2. plugins: [
  3. require("autoprefixer")({
  4. overrideBrowserslist: ["last 2 versions", ">1%"]
  5. })
  6. ]
  7. }

watch

watch选项用于开启文件监听,轮询判断文件是否发生了变化,监听到文件发生变化之后,会重新打包。

  1. watch: true, // 默认false,不开启
  2. // 配合watch,只有开启才有作⽤
  3. watchOptions: {
  4. // 默认为空,不监听的⽂件或者⽬录,⽀持正则
  5. ignored: /node_modules/,
  6. // 监听到⽂件变化后,等300ms再去执⾏,默认300ms,
  7. aggregateTimeout: 300,
  8. // 判断⽂件是否发⽣变化是通过不停的询问系统指定⽂件有没有变化,默认每秒问1次
  9. poll: 1000 // ms
  10. }

plugins

plugin 可以在 webpack 运行到某一阶段的时候, 注入扩展逻辑,改变构建结果或者做一些你想做的事情。插件作用于整个构建过程。

  1. plugins: [
  2. new HtmlWebpackPlugin({
  3. title: "首页",
  4. template: "./src/index.html",
  5. inject: true,
  6. chunks: ["index"],
  7. filename: "index.html"
  8. }),
  9. new HtmlWebpackPlugin({
  10. title: "注册",
  11. template: "./src/index.html",
  12. inject: true,
  13. chunks: ["login"],
  14. filename: "login.html"
  15. }),
  16. new CleanWebpackPlugin(),
  17. new MiniCssExtractPlugin({
  18. filename: "[name]_[contenthash:8].css"
  19. })
  20. ]

HtmlWebpackPlugin

htmlwebpackplugin 会在打包结束后,⾃动⽣成⼀个 html ⽂件,并把打包⽣成的 js 模块引⼊到该 html 中。

  1. title: HTML 文档的标题,需要使用ejs模板语法形式配置:{%= o.htmlWebpackPlugin.options.title %}
  2. filename: 输出的 HTML 的⽂件名称,默认是 index.html, 可以为输出文件指定子目录位置(例如'html/index.html'
  3. template: 模板⽂件路径
  4. inject: 配置生成的js文件插入到模板中的位置
  5. true 默认值,script标签位于html文件的 body 底部
  6. 'body' script标签位于html文件的 body 底部
  7. 'head' script标签位于html文件的 head
  8. false 不插入生成的js文件,这个几乎不会用到的
  9. favicon: 添加特定的 favicon 路径到输出的 HTML ⽂件中
  10. minify: Boolean | Object,是否启用 html-minifier 对代码进行压缩,默认是 falsehtml-webpack-plugin 内部集成了 html-minifier 插件,可以传递一个对象对 html-minifier 进行配置
  11. hash: true | false, 如果为 true, 将添加⼀个唯⼀的 webpack 编译 hash 到所有包含的脚本和 CSS ⽂件,对于解除 cache 很有⽤
  12. cache: true | false,如果为 true, 这是默认值,仅仅在⽂件修改之后才会生成新文件
  13. showErrors: true | false, 如果为 true, 这是默认值,错误信息会写⼊到 HTML ⻚⾯中
  14. chunks: 允许插入到模板中的一些chunk,不配置此项默认会将 entry 中所有的 chunk 注入到模板中。在配置多个页面时,每个页面注入的 chunk 应该是不相同的,需要通过该配置为不同页面注入不同的thunk
  15. chunksSortMode: 允许控制 chunk 在添加到⻚⾯之前的排序⽅式,⽀持的值: 'none' | 'default' | {function}-default:'auto'
  16. excludeChunks: 允许跳过某些 chunk (⽐如,跳过单元测试的chunk)

clean-webpack-plugin

  1. // 清空 dist 文件夹
  2. const { CleanWebpackPlugin } = require("clean-webpackplugin");
  3. ...
  4. plugins: [
  5. new CleanWebpackPlugin()
  6. ]

mini-css-extract-plugin

  1. // 把 css-loader 合成的 css 放到一个单独的文件中
  2. const MiniCssExtractPlugin = require("mini-css-extractplugin");
  3. {
  4. test: /\.css$/,
  5. use: [MiniCssExtractPlugin.loader, "css-loader"]
  6. }
  7. new MiniCssExtractPlugin({
  8. filename: "[name][chunkhash:8].css"
  9. })

sourceMap

源代码与打包后的代码映射关系,通过sourceMap定位到源代码。
在 development 模式中,默认开启,关闭的话 可以在配置⽂件⾥修改 devtool

  1. devtool: 'none'

eval:速度最快,使⽤ eval 包裹模块代码,
source-map:产⽣ .map ⽂件
cheap:较快,不⽤管列的信息,也不包含 loader 的 sourcemap
module:第三⽅模块,包含 loader 的 sourcemap(⽐如 jsx to js , babel 的sourcemap)
inline: 将 .map 作为DataURI嵌⼊,不单独⽣成 .map ⽂件

推荐配置:

  1. devtool: 'cheap-module-eval-source-map', // 开发环境配置
  2. devtool: 'cheap-module-source-map', // 线上⽣成配置

webpackDevServer

每次改完代码都需要重新打包⼀次,打开浏览器,刷新⼀次,很麻烦。我们可以安装使⽤ webpackdevserver 来提升开发体验,devServer把打包后的模块放到内存中,从⽽提升加载速度。

处理跨域问题

联调期间,前后端分离,直接获取数据会跨域,上线后我们使⽤ nginx 转发,开发期间, webpack 就可以搞定这件事。
启动⼀个服务器, mock⼀个接⼝:

  1. const express = require("express");
  2. const app = express();
  3. app.get("/api/info", (req, res) => {
  4. res.json({
  5. name: "webpack",
  6. age: 5,
  7. msg: "欢迎学习webpack"
  8. });
  9. });
  10. app.listen("9092");

webpackDevServer配置代理

  1. // 测试跨域问题
  2. import axios from 'axios'
  3. axios.get('/api/info').then(res=>{
  4. console.log(res)
  5. })
  6. devServer: {
  7. contentBase: "./dist", // 默认是 './dist'
  8. open: true,
  9. port: 8081,
  10. proxy: {
  11. '/api': {
  12. target: 'http://localhost:9092'
  13. }
  14. }
  15. }