webpack配置项

334 阅读9分钟

本教程使用的webpack及脚手架对应的版本如下

  • "webpack": "^4.29.0",
  • "webpack-dev-server": "3.11.0",
  • "webpack-cli": "^3.3.12"

  • "webpack": "^4.5.0",
  • "webpack-dev-server": "^3.1.3",
  • "webpack-cli": "^3.1.1"

entry

定义

开始应用程序打包过程的一个或多个起点。如果传入数组,则会处理所有条目。

动态加载的模块 不是 入口起点。

一个需要考虑的规则:每个 HTML 页面都有一个入口起点。单页应用(SPA):一个入口起点,多页应用(MPA):多个入口起点。

module.exports = {
  //...
  entry: {
    home: './home.js',
    about: './about.js',
    contact: './contact.js',
  },
};

配置项说明

(1)取值

如果传入一个字符串或字符串数组,chunk 会被命名为 main。如果传入一个对象,则每个属性的键(key)会是 chunk 的名称,该属性的值描述了 chunk 的入口点。

  • 当entry是一个字符串时,这个字符串表示需要打包的模块路径.
  • 当entry是数组 时,当需要将多个模块打包成一个模块,可以使用这个方式,如果这些模块之间不存在依赖,数组中值的顺序没有要求,如果存在依赖,则要将依赖性最高的模块放在最后面. eg:
entry:[ "./app/one.js","app/two.js" ]
  • 当entry是键值对形式的对象时,当需要分别打包成多个模块时,可以使用这种方式. eg:
entry:{ 
    module1:"./app/one.js", 
    module2:[ "./app/two.js","./app/three.js" ] 
}

注:当entry是一个键值对形式的对象时,包名就是键名,output的filename不能是一个固定的值,因为每个包的名字不能一样.

output

定义

output 位于对象最顶级键(key),包括了一组选项,指示 webpack 如何去输出、以及在哪里输出你的「bundle、asset 和其他你所打包或使用 webpack 载入的任何内容」。

output 配置如何输出最终想要的代码。 output 是一个 object ,里面包含一系列配置项,下面分别介绍它们。

配置项说明

(1)filename

  • 官网: www.webpackjs.com/configurati…
  • 类型:字符串,string function (pathData, assetInfo) => string
  • 作用:此选项决定了每个输出 bundle 的名称。这些 bundle 将写入到 output.path 选项指定的目录下。

对于单个入口起点,filename 会是一个静态名称。

配置输出文件的名称,为string 类型。 如果只有一个输出文件,则可以把它写成静态不变的:

filename: 'bundle.js'

但是有多个 Chunk 要输出时,就需要借助模版和变量了。Webpack 会为每个 Chunk取一个名称,可以根据 Chunk 的名称来区分输出的文件名:

filename: '[name].js'

代码里的 [name] 代表用内置的 name 变量去替换 [name] ,这时你可以把它看作一个字符串模块函数, 每个要输出的 Chunk 都会通过这个函数去拼接出输出的文件名称。

内置变量除了 name 还包括:

变量名含义
idChunk的唯一标识,从0开始
nameChunk的名称
hashChunk的唯一标识的Hash值
chunkhashChunk内容的Hash值

它们可以:控制客户端缓存

[hash][chunkhash]都与chunk内容直接相关,如果在filename中使用,当chunk的内容改变时,可以同时引起资源文件名的更改,从而使用户在下一次请求资源文件时会立即下载新的版本而不会使用本地缓存

其中 hash 和 chunkhash 的长度是可指定的, [hash:8] 代表取8位 Hash 值,默认是20位。

注意 ExtractTextWebpackPlugin 插件是使用 contenthash 来代表哈希值而不是 chunkhash, 原因在于 ExtractTextWebpackPlugin 提取出来的内容是代码内容本身而不是由一组模块组成的 Chunk。

filename可以不仅仅是bundle的名字,还可以是一个相对路径

即便路径中的目录不存在也没关系,Webpack会在输出资源时创建该目录。

eg:

module.exports = {
  //...
  output: {
    filename: 'bundle.js',
  },
};
module.exports = {
  //...
  output: {
    filename: '[name].bundle.js',
  },
};
module.exports = {
  //...
  output: {
    filename: 'static/js/[name].[hash].js',
  },
};
module.exports = {
    entry:{
        main:'./src/main.js',
        vender:'./src/vender.js'
    },
    output: {
      filename: '[name].js',
    },
 };

打包后如下:

image.png

filename中的[name]会被替换为chunk name即main和vender。因此最后会生成vendor.jsmain.js

index.html自动帮我们将生成的bundle添加到html中呢?这里可以用到插件 HtmlWebpackPlugin

output.filename规定的是应用入口文件的名称,而output.entry提供的是webpack打包的入口。某种情况下这两个入口是统一的。

通过webpack打包后的应用入口是webpack生成的manifest + runtime。当没有分离manifest + runtime的时候,这部分生成的内容会和entry字段提供的文件相同

(2)chunkFilename

chunkFilename 指未被列在 entry 中,却又需要被打包出来的 chunk 文件的名称。一般来说,这个 chunk 文件指的就是要懒加载的代码

chunkFilename 和上面的 filename 非常类似,但 chunkFilename 只用于指定在运行过程中生成的 Chunk 在输出时的文件名称。

常见的会在运行时生成 Chunk 场景有在使用 CommonChunkPlugin、使用 import('path/to/module') 动态加载等时。 chunkFilename 支持和 filename 一致的内置变量

eg:

module.exports = {
  //...
  output: {
    //...
    chunkFilename: '[id].js',
  },
};
module.exports = {
  //...
  output: {
    //...
    chunkFilename: 'static/js/common.[id].[hash].js'
  },
};

(3)path

  • 官网:www.webpackjs.com/configurati…
  • 类型:string = path.join(process.cwd(), 'dist')
  • 作用:output.path 配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。通常通过 Node.js 的 path 模块去获取绝对路径:
path: path.resolve(__dirname, 'dist_[hash]')

path指定资源输出的位置,要求值必须为绝对路径

const path=require('path')
module.exports={
    entry:'./src/main.js',
    output:{
        filename:'bundle.js',
        //将资源输出位置设置为该项目的dist目录
        path: path.resolve(__dirname, 'dist')
    },
}
module.exports={
    entry:'./src/main.js',
    output:{
        path: __dirname + '/dist',
    },
}

在Webpack 4之后,output.path已经默认为dist目录。除非我们需要更改它,否则不必单独配置,不需要写。

(4)publicPath

  • 官网:www.webpackjs.com/configurati…
  • 类型:function/ string
  • 作用:publicPath是一个非常重要的配置项,用来指定资源的请求位置。该选项的值是以 runtime(运行时) 或 loader(载入时) 所创建的每个 URL 为前缀。因此,在多数情况下,此选项的值都会以 / 结束
module.exports={
    entry:'./src/main.js',
    output:{
        path: __dirname + '/dist',
        publicPath: '/'
    },
}

原本图片请求的地址是./img.jpg,而在配置上加上publicPath后,实际路径就变成了了./dist/static/img/img.jpg,这样就能从打包后的资源中获取图片了

image.png

在复杂的项目里可能会有一些构建出的资源需要异步加载,加载这些异步资源需要对应的 URL 地址。

output.publicPath 配置发布到线上资源的 URL 前缀,为string 类型。 默认值是空字符串 '',即使用相对路径。

这样说可能有点抽象,举个例子,需要把构建出的资源文件上传到 CDN 服务上,以利于加快页面的打开速度。配置代码如下:

filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'

这时发布到线上的 HTML 在引入 JavaScript 文件时就需要:

<script src='https://cdn.example.com/assets/a_12345678.js'></script>

使用该配置项时要小心,稍有不慎将导致资源加载404错误。

output.pathoutput.publicPath 都支持字符串模版,内置变量只有一个:hash 代表一次编译操作的 Hash 值。

loader

定义

webpack 只能理解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供应用程序使用,以及被添加到依赖图中。

loader 用于对模块的源代码进行转换。loader 可以使你在 import 或 "load(加载)" 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS 文件!

webpack是一款强大的模块打包工具,它可以引入配置文件完成前端高度定制化的构建工作.

webpack默认只能理解JavaScriptJSON文件,但实际工作中各种需求层出不穷,文件类型也多种多样.比如.vue.ts图片.css等,这就需要loader增强webpack处理文件的能力.

配置项说明

(1)test及use属性

在更高层面,在 webpack 的配置中,loader 有两个属性:

  1. test 属性,识别出哪些文件会被转换。
  2. use 属性,定义出在进行转换时,应该使用哪个 loader。

webpack.config.js

const path = require('path');

module.exports = {
  output: {
    filename: 'my-first-webpack.bundle.js',
  },
  module: {
    rules: [{ test: /.txt$/, use: 'raw-loader' }],
  },
};

以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use

在 webpack 配置中定义 rules 时,要定义在 module.rules 而不是 rules 中。

(2)举例

例如,你可以使用 loader 告诉 webpack 加载 CSS 文件,或者将 TypeScript 转为 JavaScript。为此,首先安装相对应的 loader:

npm install --save-dev css-loader ts-loader 然后指示 webpack 对每个 .css 使用 css-loader,以及对所有 .ts 文件使用 ts-loader

webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /.css$/, use: 'css-loader' },
      { test: /.ts$/, use: 'ts-loader' },
    ],
  },
};

(3)使用loader

在你的应用程序中,有两种使用 loader 的方式:

  • 配置方式(推荐):在 webpack.config.js 文件中指定 loader。
  • 内联方式:在每个 import 语句中显式指定 loader。

注意在 webpack v4 版本可以通过 CLI 使用 loader,但是在 webpack v5 中被弃用。

配置方式

module.rules 允许你在 webpack 配置中指定多个 loader。 这种方式是展示 loader 的一种简明方式,并且有助于使代码变得简洁和易于维护。同时让你对各个 loader 有个全局概览:

loader 从右到左(或从下到上)地取值(evaluate)/执行(execute)。在下面的示例中,从 sass-loader 开始执行,然后继续执行 css-loader,最后以 style-loader 为结束。

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          // [style-loader](/loaders/style-loader)
          { loader: 'style-loader' },
          // [css-loader](/loaders/css-loader)
          {
            loader: 'css-loader',
            options: {
              modules: true
            }
          },
          // [sass-loader](/loaders/sass-loader)
          { loader: 'sass-loader' }
        ]
      }
    ]
  }
};
module.exports = {
  //...
  module: {
    rules: [
      {
        test: /.less/,
        use: ['style-loader','less-loader'],
      },
    ],
  },
};

内联方式

可以在 import 语句或任何 与 "import" 方法同等的引用方式 中指定 loader。使用 ! 将资源中的 loader 分开。每个部分都会相对于当前目录解析。

import Styles from 'style-loader!css-loader?modules!./styles.css';

plugin

定义

loader 用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。包括:打包优化,资源管理,注入环境变量。

pluginswebpack执行打包过程中某个节点,需要的做的事情。

想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建一个插件实例。

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack'); // 用于访问内置插件

module.exports = {
  module: {
    rules: [{ test: /.txt$/, use: 'raw-loader' }],
  },
  plugins: [new HtmlWebpackPlugin({ template: './src/index.html' })],
};

在上面的示例中,html-webpack-plugin 为应用程序生成一个 HTML 文件,并自动将生成的所有 bundle 注入到此文件中。

重要的plugins

(1)HtmlWebpackPlugin

  • HtmlWebpackPlugin的作用是:在webpack打包项目结束时,生成一个html文件,并将打包好的js文件引入到html中;
  • HtmlWebpackPlugin 的使用
    • 安装: npm i html-webpack-plugin -D
    • 配置
  const path = require('path');
  // 引入HtmlWebpackPlugin
  const HtmlWebpackPlugin = require('html-webpack-plugin')
  module.exports = {
  	//  入口文件
  	entry: './src/index.js',
  	output: {
  		// 输出文件名
  		filename: 'built.js',
  		// 输出文件路径
  		path: path.resolve(__dirname,'dist')
  	},
  	plugins: [
  			// 使用 HtmlWebpackPlugin
  			new HtmlWebpackPlugin({
  				// 传入一个生成html的模板
  				template: 'src/index.html'
  			})
  	]
  	// 打包模式有两种:development和production;默认是production模式,会自定压缩代码
  	mode: 'development'
  }

(2)CleanWebpackPlugin

  • CleanWebpackPlugin的作用是:在webpack打包开始时,自动删除之前打包的文件dist;
  • CleanWebpackPlugin的使用
    • 安装:npm i clean-webpack-plugin -D
    • 配置
  const path = require('path');
  	// 引入HtmlWebpackPlugin
  	const HtmlWebpackPlugin = require('html-webpack-plugin')
  	// 引入CleanWebpackPlugin
  	const CleanWebpackPlugin = require('clean-webpack-plugin')
  	module.exports = {
  		//  入口文件
  		entry: './src/index.js',
  		output: {
  			// 输出文件名
  			filename: 'built.js',
  			// 输出文件路径
  			path: path.resolve(__dirname,'dist')
  		},
  		plugins: [
  				// 使用 HtmlWebpackPlugin
  				new HtmlWebpackPlugin({
  					// 传入一个生成html的模板
  					template: 'src/index.html'
  				}),
  				// 使用 CleanWebpackPlugin
  				new CleanWebpackPlugin(['dist'])
  		]
  		// 打包模式有两种:development和production;默认是production模式,会自定压缩代码
  		mode: 'development'
  	}

(3)MiniCssExtractPlugin

  • 作用:将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
  • 使用:
    • 安装:$ npm install mini-css-extract-plugin
    • 配置:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
   new HtmlWebpackPlugin(),
   new MiniCssExtractPlugin()
  ]
}
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    entry: './src/js/app.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'output.bundle.js'
    },
    plugins: [new MiniCssExtractPlugin({
        filename: "[name].css",
        chunkFilename: "[id].css"
    })],
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/i,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 211192
                        }
                    }
                ]
            },
            {
                test: /\.(m?js|jsx)$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: ['@babel/plugin-transform-react-jsx']
                    }
                }
            },
            // {
            //     test: /\.s[ac]ss$/i,
            //     use: [
            //         // 将 JS 字符串生成为 style 节点
            //         'style-loader',
            //         // 将 CSS 转化成 CommonJS 模块
            //         'css-loader',
            //         // 将 Sass 编译成 CSS
            //         'sass-loader',
            //     ],
            // },
            {
                test: /\.s[ac]ss$/i,
                use: [
                    // process.env.NODE_ENV !== 'production'?'style-loader':MiniCssExtractPlugin.loader
                    MiniCssExtractPlugin.loader,
                    // 将 CSS 转化成 CommonJS 模块
                    'css-loader',
                    // 将 Sass 编译成 CSS
                    'sass-loader',
                ],
            },
        ]
    }
}

其他的插件用法也大致如此,如果你需要更多满足你需要的 plugins,可以到这个官方列表中进行搜索

mode

定义

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。

通过选择 developmentproduction 或 none 之中的一个,来设置 mode 参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为 production

用法

(1)只需在配置对象中提供 mode 选项:

module.exports = {
  mode: 'development',
};

(2)从命令行 CLI 参数中传递

webpack --mode=development

CLI

定义

为了更合适且方便地使用配置,可以在 webpack.config.js 中对 webpack 进行配置。CLI 中传入的任何参数会在配置文件中映射为对应的参数。

yargs介绍

定义

命令行参数解析工具yargs

Yargs 框架通过使用 Node.js 构建功能全面的命令行应用,它能轻松配置命令,解析多个参数,并设置快捷方式等,还能自动生成帮助菜单。lerna源码使用yargs。

使用

  • 安装:`npm i yargs -D
  • 引入:const yargs = requier('yargs/yargs')import yargs from 'yargs' // 从v16起,支持ESM import
  • 本地初始化项目
$ mkdir demo
$ cd demo
$ npm init -y
  • 在package里面加入bin
{
  "name": "demo",
  ···
  "bin":{
      "cli-test":"bin/index.js"
  }
}
  • 创建一个index.js,在js文件的开头加入#!/usr/bin/env node
#!/usr/bin/env node


const yargs = require('yargs/yargs')
const {hideBin} = require('yargs/helpers')
const arg = hideBin(process.argv)
// hideBin功能相当于process.argv.slice(2)。但是他兼容环境的变化。如Electron

const cli = yargs(arg)
console.log(cli)

#!/usr/bin/env node 用于指明该脚本文件要使用node来执行。

  • 在根目录执行npm link 给cli-test添加软连接。后面可以直接在控制台输入cli-test

$ cli-test

cli Jt {
  customScriptName: false,
  parsed: false,
  '$0': 'cli-text',
  argv: [cli-test]
}

$ cli-text  --version
$ cli-text  --help

yargs自带version和help的功能。

简单模式

yargs默认使用两个--作为参数的前缀,中间使用空格或者=都可以

下面的代码展示了yargs最简单的用法,你只需要引入yargs,就能读取命令行参数,不需要写任何的配置,非常的简单

var argv = require('yargs').argv;

if (argv.ships > 3 && argv.distance < 53.5) {
    console.log('Plunder more riffiwobbles!');
} else {
    console.log('Retreat from the xupptumblers!');
}
$ ./plunder.js --ships=4 --distance=22
Plunder more riffiwobbles!

$ ./plunder.js --ships 12 --distance 98.7
Retreat from the xupptumblers!
  • 简单模式还能读取短变量如-x 4相当于argv.x = 4
  • 简单模式还能读取布尔类型-s相当于argv.s = true
  • 简单模式还能读取非-开始的变量,这种类型的变量保存在argv._数组里面