【工程】webpack 系列 — 常用扩展

722 阅读4分钟

打算系统的整理一下,webpack 的一些知识点,也是时候结合项目中使用的一些 案例,做一些总结了。

webpack系列 打算从 webpack核心功能 -> 常用扩展 -> CSS 工程化 -> JS 兼容性 -> 性能优化 这几个方面开始记录。

以及结合一些案例,方便大家阅读和实践,以备 开箱即用

仓库地址:PantherVkin/webpack-note (github.com)

清除输出目录

clean-webpack-plugin - npm (npmjs.com)

  1. 安装
$ npm i -D clean-webpack-plugin
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: '[name].[chunkhash:5].js'
  },
  plugins: [new CleanWebpackPlugin()]
}

自动生成页面

html-webpack-plugin - npm (npmjs.com)

简单配置

  1. 安装
$ npm i -D html-webpack-plugin
  1. 创建模板文件public/template.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>webpack</h1>
    <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Assumenda, deserunt ducimus. Et iure labore debitis tempora praesentium atque velit provident recusandae dolor harum fugiat facere totam, maiores repudiandae illum aliquid?
    </p>
</body>
</html>
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: '[name].[chunkhash:5].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/template.html',
      filename: 'a.html'
    })
  ]
}

image.png

多入口

  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  entry: {
    home: './src/index.js',
    a: './src/a.js'
  },
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: '[name].[chunkhash:5].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/template.html',
      filename: 'a.html'
    })
  ]
}

image.png

单页面方式

  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  entry: {
    home: './src/index.js',
    a: './src/a.js'
  },
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: 'scripts/[name].[chunkhash:5].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/template.html',
      filename: 'home.html',
      chunks: ['home']
    }),
    new HtmlWebpackPlugin({
      template: './public/template.html',
      filename: 'a.html',
      chunks: ['a']
    })
  ]
}

image.png

复制静态资源

copy-webpack-plugin - npm (npmjs.com)

  1. 安装
$ npm i -D copy-webpack-plugin
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: 'scripts/[name].[chunkhash:5].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    }),

    new CopyPlugin({
      patterns: [{from: './public/*', to: './'}]
    })
  ]
}

开发服务器

开发中 Server(devServer) | webpack 中文网 (webpackjs.com)

  1. 安装
$ npm i -D webpack-dev-server
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: 'scripts/[name].[chunkhash:5].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],
  devServer: {
    port: 8000,
    open: true,
    proxy: {
      //代理规则
      '/api': {
        target: 'http://open.xxxx',
        changeOrigin: true //更改请求头中的host和origin
      }
    }
  },
  stats: {
    modules: false,
    colors: true
  }
}
  1. 执行 npx webpack-dev-server

webpack-dev-server命令几乎支持所有的webpack命令参数,如--config-env等等,你可以把它当作webpack命令使用。

这个命令是专门为开发阶段服务的,真正部署的时候还是得使用webpack命令。

  • 当我们执行webpack-dev-server命令后,它做了以下操作

内部执行webpack命令,传递命令参数。

开启watch。

注册hooks:类似于plugin,webpack-dev-server会向webpack中注册一些钩子函数,主要功能如下:

将资源列表(aseets)保存起来。

禁止webpack输出文件。

用express开启一个服务器,监听某个端口,当请求到达后,根据请求的路径,给予相应的资源内容。

普通文件处理

file-loader

  1. 原理

生成依赖的文件到输出目录,然后将模块文件设置为:导出一个路径

//file-loader
function loader(source){
	// source:文件内容(图片内容 buffer)
	// 1. 生成一个具有相同文件内容的文件到输出目录
	// 2. 返回一段代码   export default "文件名"
}
  1. 安装
$ npm i -D file-loader
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: 'scripts/[name].[chunkhash:5].js'
  },
  module: {
    rules: [
      {
        test: /\.(png)|(gif)|(jpg)$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: 'imgs/[name].[hash:5].[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],
  stats: {
    modules: false,
    colors: true
  }
}

  1. 完整案例

webpack-note/examples/2.5-普通文件处理/1-file-loader at master · PantherVkin/webpack-note (github.com)

url-loader

  1. 原理

将依赖的文件转换为:导出一个base64格式的字符串。

//-loader
function loader(source){
	// source:文件内容(图片内容 buffer)
	// 1. 根据buffer生成一个base64编码
	// 2. 返回一段代码   export default "base64编码"
}
  1. 安装

url-loader 封装了 file-loader, 所以我们可以只需要安装 url-loader就可以了。

$ npm i -D url-loader
  1. webpack.config.js
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map',
  output: {
    path: path.resolve(__dirname, 'target'),
    filename: 'scripts/[name].[chunkhash:5].js'
  },
  module: {
    rules: [
      {
        test: /\.(png)|(gif)|(jpg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              // limit: false //不限制任何大小,所有经过loader的文件进行base64编码返回
              limit: 10 * 1024, //只要文件不超过 10*1024 字节,则使用base64编码,否则,交给file-loader进行处理
              name: 'imgs/[name].[hash:5].[ext]'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],
  stats: {
    modules: false,
    colors: true
  }
}
  1. 完整案例

webpack-note/examples/2.5-普通文件处理/2-url-loader at master · PantherVkin/webpack-note (github.com)

解决路径问题

webpack4

在使用file-loaderurl-loader时,可能会遇到一个非常有趣的问题?

  1. 比如,通过webpack打包的目录结构如下:
dist
    |—— img
        |—— a.png  #file-loader生成的文件
    |—— scripts
        |—— main.js  #export default "img/a.png"
    |—— html
        |—— index.html #<script src="../scripts/main.js" ></script>
  1. 这种问题发生的根本原因:

模块中的路径来自于某个loader或plugin,当产生路径时,loader或plugin只有相对于dist目录的路径,并不知道该路径将在哪个资源中使用,从而无法确定最终正确的路径。

image.png

  1. 面对这种情况,需要依靠webpack的配置publicPath解决。

会把路径拼接到publicPath后面。

image.png

  1. 完整案例

webpack-note/examples/2.6-解决路径问题/1-webpack4 at master · PantherVkin/webpack-note (github.com)

webpack5

不会存在这个问题。

  1. 完整案例

webpack-note/examples/2.6-解决路径问题/2-webpack5 at master · PantherVkin/webpack-note (github.com)

image.png

webpack内置插件

所有的webpack内置插件都作为webpack的静态属性存在的,使用下面的方式即可创建一个插件对象。

const webpack = require("webpack")

new webpack.插件名(options)

DefinePlugin

全局常量定义插件,使用该插件通常定义一些常量值,例如:

new webpack.DefinePlugin({
    PI: `Math.PI`, // PI = Math.PI
    VERSION: `"1.0.0"`, // VERSION = "1.0.0"
    DOMAIN: JSON.stringify("duyi.com")
})

这样一来,在源码中,我们可以直接使用插件中提供的常量,当webpack编译完成后,会自动替换为常量的值

BannerPlugin

它可以为每个chunk生成的文件头部添加一行注释,一般用于添加作者、公司、版权等信息

new webpack.BannerPlugin({
  banner: `
  hash:[hash]
  chunkhash:[chunkhash]
  name:[name]
  author:yuanjin
  corporation:duyi
  `
})

ProvidePlugin

自动加载模块,而不必到处 import 或 require

new webpack.ProvidePlugin({
  $: 'jquery',
  _: 'lodash'
})

然后在我们任意源码中:

$('#item'); // <= 起作用
_.drop([1, 2, 3], 2); // <= 起作用