[Webpack] 核心概念、基础配置、常用loader和常用插件

Webpack 是一个JavaScript应用程序的打包模块化工具.Webpack里一切文件都是模块,处理应用程序时,它会递归构建程序中各个模块的依赖关系图, 最后将这些模块打包成一个或者多个 bundle

核心概念

入口(enrty)

入口起点指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。

出口(output)

output属性告诉 webpack 在哪里输出它所创建的 bundles ,以及如何命名这些文件,默认值为 ./dist 。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。可以通过在配置中指定一个 output 字段,来配置这些处理过程。

loader

loade 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后就可以利用 webpack 的打包能力,对它们进行处理。本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。

插件(plugins)

loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。

模式

通过选择 developmentproduction 之中的一个,来设置 mode 参数,可以启用相应模式下的 webpack 内置的优化。

基础配置

可以通过一个JavaScript文件导出Webpack的配置:

module.exports = {
  mode: "development",	// 模式
  entry: {},	// 入口
  output: {},	// 输出
  resolve: {},	// 解析
  module: {},	// 模块
  plugins: [],	// 插件
}
复制代码

mode

mode 的取值有 developmentproduction 。通过设置 mode ,webpack在打包时会使用相应模式的内置优化,并 process.env.NODE_ENV 设置为对应的值。

entry

entry是应用的入口,可以传入一个字符串、数组或者对象。如果传入一个字符串或字符串数组,chunk 会被命名为 main 。如果传入一个对象,则每个键(key)会是 chunk 的名称,该值描述了 chunk 的入口起点。

module.exports = {
    // ...
    entry: {
        app: "./src/index.js"
    }
}
复制代码

output

output 可以控制 webpack 如何向硬盘写入编译文件。即使可以存在多个 入口 起点,但只指定一个 输出 配置。

  • output.path : 指定打包后内容的输出目录

  • output.filename : 配置每个输出 bundle 的名称,可以使用模板字符串配置输出。

    模板 描述
    [hash] 模块标识符的 hash
    [chunkhash] chunk 内容的 hash
    [name] 模块名称
    [id] 模块标识符
    [query] 模块的 query
  • output.chunkFilename :配置非入口 chunk 文件的名称,默认 [id].js ,与 filename 选项一致可以使用模板字符串。

  • output.publicPath :指定在浏览器中所引用的此输出目录对应的 公开 URL

module.export = {
    // ...
    output: {
        path: "./dist",
        publicPath: "https://example.com",
        filename: "[name].[chunkhash].js",
        chunkFilename:  "[name].[chunkhash].js"
    }
}
复制代码

resolve

resolve 设置模块如何被解析。

resolve.alias
resolve.modules
module.exports = {
    // ...
    resolve: {
        alias: {
            "@src": "./src/"
        },
        modules: ["./node_modules"]
    }
}
复制代码

module

module 设置webpack如何处理不同类型的模块。

  • module.rules :配置规则数组。在创建模块时,匹配对应的规则并应用 loader 处理模块。

规则( Rule )的配置:

  • rule.test :匹配模块文件路径
  • rule.include :匹配目录下的文件
  • rule.exclude :匹配不在目录下的文件
  • rule.use :使用 loaderloader 应用顺序为从右到左
module.exports = {
    // ...
    rules: [{
        test: /.js$/,
        include: ['./src'],
        use: ["babel-loader"]
    }]
}
复制代码

plugins

plugins 设置打包过程中使用的插件。

module.exports = {
    // ...
    plugins: []
}
复制代码

devtool

设置 source maps 如何生成,开发时可以将此选项设置为 cheap-module-eval-source-map

module.exports = {
    // ...
    devtool: "cheap-module-eval-source-map"
}
复制代码

devServer

设置 webpack-dev-server 使用时的选项,可以配置监听端口、代理等。

const path = require("path")
module.exports = {
    // ...
    devServer: {
        host: "0.0.0.0",
        contentBase: path.resolve(__dirname, "build"),
		hot: true,	// 开启模块热替换
		historyApiFallback: true,  // 使用index.html页面来代替404响应,使用HTML5 History API时可将该选项设置为true,例如react-router
		proxy: {
            '/api': 'http://127.0.0.1:3000'
        }
    }
}
复制代码

常用 loader

CSS相关

用于解析 CSSloader 一般有: style-loadercss-loaderpostcss-loaderless-loadersass-loader

  • style-loader :通过注入 <style> 标签将CSS添加到DOM
  • css-loader :解释 @importurl() ,会 import/require() 后再解析它们。 css-loader 前应用了 loader 需要指定 importLoaders 选项
  • postcss-loader :应用 postcss
  • less-loader :解析 less
  • sass-loader :解析 sass
module.exports = {
    // ...
    module: {
        rules: [{
            test: /.less$/,
            include: ["./src"],
            use: [
                "style-loader",
                {
                    loader: "css-loader",
                    options: {
                        importLoaders: 2
                    }
                },
                "postcss-loader",
                "less-loader"
            ]
        }]
    }
}
复制代码

JavaScript相关

  • babel-loaderbabel-loader 基于 babel ,用于解析 JavaScript 文件。 babel 有丰富的预设和插件, babel 的配置可以直接写到 options 里或者单独写道配置文件里。

几个 babel 常用的预设和插件:

  • @babel/preset-env :用于转换最新的 JavaScript 代码、为低版本浏览器提供 polyfill
  • @babel/preset-react :用于解析 jsx 内容,该预设包含了 @babel/plugin-syntax-jsx@babel/plugin-transform-react-jsx@babel/plugin-transform-react-display-name 三个插件。当指定了 development 选项时,还额外包含 @babel/plugin-transform-react-jsx-self@babel/plugin-transform-react-jsx-source 两个插件
  • @babel/preset-typescript :用于解析 typescript 内容,该预设仅包含 @babel/plugin-transform-typescript 插件。在解析 typescript 内容时,该预设会直接把 typescript 相关的内容去掉
  • @babel/plugin-proposal-class-properties :用于解析类属性的插件
  • @babel/plugin-proposal-object-rest-spread :用于解析析构对象的插件
  • @babel/plugin-transform-runtime :用于复用 babel 内置的 helper 代码从而减小代码体积

babel 常用的预设有 preset-envpreset-reactpreset

module.export = {
    // ...
    module: {
        rules: [{
            test: /.js$/,
            include: ["./src/"],
            use: [{
                loader: "babel-loader",
                options: {
                    presets: [
                       "@babel/preset-env",
                        "@babel/preset-react",
                        "@babel/preset-typescript",
                    ],
                    plugins: [
                        "@babel/plugin-proposal-class-properties",
   						 "@babel/plugin-proposal-object-rest-spread",
                    ]
                }
            }]
        }]
    }
}
复制代码

其他资源

除了 CSSJavaScript 资源外,项目里还有其他的资源,例如图片、字体等。对于这类资源,可以通过 file-loaderurl-loader 解析。

  • file-loader :告诉 Webpack 引用的模块是一个文件,并返回其打包后的 url
  • url-loader :作用与 file-loader 类似,但当文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL。
module.exports = {
    // ...
    module: {
        rules: [{
        	test: /\.(png|jpg|gif)$/,
        	use: [{
            	loader: 'url-loader',
            	options: {
              		limit: 8192
            	}
          	}]
        }]
    }
}
复制代码

常用插件

copy-webpack-plugin

copy-webpack-plugin 用于打包时复制文件。

const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
    // ...
    plugins: [
        new CopyWebpackPlugin({
        	{
        		from: "./public",
        		to: "./build/"
      		}
        })
    ]
} 
复制代码

html-webpack-plugin

生成一个 HTML5 文件,包括使用 script 标签的 body 中的所有 webpack 包。

const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
	// ...
	plugins: [
        new HtmlWebpackPlugin({
            template: "./public/index.html",
      		chunks: ["app"]
        })
    ]
};
复制代码

add-asset-html-webpack-plugin

插入一个 JavaScript 或者 CSS 资源到 html-webpack-plugin 生产的 html 页面中。使用 DLL 时,可以通过该插件将生成的 JavaScript 文件插入到页面中。

const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const path = require("path")
module.exports = {
	// ...
	plugins: [
		new HtmlWebpackPlugin(),
		new AddAssetHtmlPlugin({
            filepath: path.resolve(__dirname, './dlls/*.dll.js'),
      		outputPath: "dlls",
      		publicPath: "/dlls"
        })
    ]
};
复制代码

clean-webpack-plugin

clean-webpack-plugin 可以清理文件,可以用于打包时清理之前打包的文件。

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
	// ...
	plugins: [
		new CleanWebpackPlugin()
    ]
};
复制代码

mini-css-extract-plugin

将CSS提取到单独的文件中,为每个包含CSS的JS文件创建一个CSS文件,同时该插件支持CSS和SourceMap的按需加载。使用该插件时, style-loader 需要替换为该插件提供的 loader

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
	// ...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,	// 需要替换 style-loader
					{
						loader: "css-loader",
						options: {
							importLoaders: 1
						}
					}
				]
            }
        ]
    },
	plugins: [
		new MiniCssExtractPlugin({
			filename: "static/css/[name].[chunkhash:8].css",
			chunkFilename: "static/css/[name].[chunkhash:8].chunk.css"
		})
    ]
};
复制代码

webpack.HotModuleReplacementPlugin

模块热替换插件,开启HMR。可以和 webpack.NamedModulesPlugin 搭配使用,显示模块的相对路径,建议用于开发环境。

const webpack = require('webpack');
module.exports = {
	// ...
	plugins: [
        new webpack.NamedModulesPlugin(),
        new webpack.HotModuleReplacementPlugin(),
    ]
};
复制代码

webpack.DefinePlugin

创建一个在 编译 时可以配置的全局常量。

const webpack = require('webpack');
module.exports = {
	// ...
	plugins: [
        new webpack.DefinePlugin({
            VERSION: JSON.stringify("0.0.1")
        })
    ]
};
复制代码

因为这个插件直接执行文本替换,给定的值必须包含字符串本身内的 实际引号 。通常,有两种方式来达到这个效果,使用 '"production"' , 或者使用 JSON.stringify('production')

webpack.DllPluginwebpack.DllReferencePlugin

DllPlugin和DllReferencePlugin提供了一种拆分包的方法,可以极大地提高构建时间性能。

// 制作dll
const webpack = require("webpack");
const path = require("path");

module.exports = {
	mode: "production",
	entry: {
        react: ["react", "react-dom"],
        antd: ["antd"],
        utils: ["lodash", "moment"]
    },
    output: {
		path: "./dlls",
		filename: "[name].dll.js",
		library: "[name]_[hash]"
	},
	resolve: {
		extensions: [".js", ".jsx"],
		modules: ["./node_modules"]
	},
	plugins: [
		new webpack.DllPlugin({
			path: path.resolve(__dirname, "./dlls/[name].manifest.json"),
			name: "[name]_[hash]"
		})
	]
};
复制代码
// 使用dll
const webpack = require("webpack");
const path = require("path");

module.exports = {
	// ...
	plugins: [
		new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/react.manifest.json"),
		}),
        new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/antd.manifest.json"),
		}),
        new webpack.DllReferencePlugin({
			manifest: path.resolve(__dirname, "./dlls/utils.manifest.json"),
		}),
		new AddAssetHtmlWebpackPlugin({
			filepath: path.resolves(__dirname,  './dlls/*.dll.js'),
			outputPath: "dlls",
			publicPath: "/dlls"
		})
	]
};
复制代码
我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章