webpack这东西面试要求要会,实际工作中接触不到,反正我接触不到,通常工作中都是有人配好了,webpack中文文档看来看去,基本概念,原理,翻来覆去看,没啥用还是不知道怎么用的,不知道有没有和我一样,所以从今天开始,我自己扒!原理啥的文档里有的我就不说了,我主要研究下怎么用!
1. webpack配置文件在哪?
其实webpack是不需要手动添加的,脚手架创建的项目都会自动有一个webpack文件,可以使用 npm run eject 命令将 webpack.config.js 暴露出来。然后在该配置文件中进行修改。但该命令是不可逆的, 一旦执行了此命令。webpack.config.js 文件就永久的暴露出来。可以使用customize-cra,
使用此库将覆盖create-react-app的
默认行为和配置。通过导入customize-cra
函数和导出我们函数中包装的一些函数调用,可以轻松地修改构成.webpack,
webpack-dev-server
babel,
create-react-app。
2.如何用?
a. 安装
//使用 customize-cra 需要依赖 react-app-rewired
npm install customize-cra react-app-rewired --dev
b. 使用:更改 package.json 中的 scripts 配置,如下所示。即用 react-app-rewired
命令代替 react-scripts
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
c. 覆盖配置webpack:在项目根目录下添加 config-overrides.js 文件。在该文件中配置 webpack。
3.config-overrides.js 中 怎么配?
//override:使用插件,这些插件调用中的每一个都将返回一个新函数,override将使用新修改的配置对象进行调用。
//addWebpackAlias:取别名的,将提供的别名信息添加到 webpack 的别名部分。传递一个包含尽可能多的条目的对象文字,整个对象将被合并。
//adjustWorkbox:调整工作箱,调整 Workbox 配置。传递将使用当前 Workbox 配置调用的函数,您可以在其中根据需要更改配置对象。
const { override, addWebpackAlias, adjustWorkbox, overrideDevServer } = require('customize-cra');
//path : node 中的模块 提供了用于处理文件和目录路径的实用程序
const path = require('path');
//覆盖
module.exports = {
webpack: override(
//写需要新修改的配置
//path.resolve()方法将一系列路径或路径段解析为绝对路径。
addWebpackAlias({ '@src': path.resolve('./src'), lodash: 'lodash-es' }),
adjustWorkbox((wb) => Object.assign(wb, { skipWaiting: true }))
),
};
4.常用配置?
a. 添加一个 babel 插件。无论你传递什么都plugin
将被添加到 Babel 的plugins
数组中。
const { addBabelPlugin } = require('customize-cra');
addBabelPlugin(['import', { libraryName: 'antd', style: true }, 'antd'])
b. output 配置
const path = require('path');
//path.join()方法path使用特定于平台的分隔符作为分隔符将所有给定的段连接在一起
//process对象提供有关和控制当前 Node.js 进程的信息。
//process.cwd()方法返回 Node.js 进程的当前工作目录。
//找到package.json中的name
const { name } = require(path.join(process.cwd(), './package.json'));
const overrideOutput = () => (config) => {
//chunkFilename : 决定了非入口(non-entry) chunk 文件的名称。
delete config.output.chunkFilename;
//filename : 决定了每个输出 bundle 的名称
config.output.filename = `static/js/${name}.js`;
//library : 将入口起点的返回值,赋值给 output.library 提供的变量名。
//libraryTarget :配置如何暴露 library。可以使用下面的选项中的任意一个。默认是var,一般设置为umd,umd将你的 library 暴露为所有的模块定义下都可运行的方式,
config.output.library = `${name}-[name]`;
config.output.libraryTarget = 'umd';
//publicPath : 指定在浏览器中所引用的「此输出目录对应的公开 URL」。此选项的值都会以/结束,默认值是''。
//env: 返回一个包含用户环境的对象,是可配置的环境变量
//NODE_ENV : 不是process.env里面的属性
config.output.publicPath = process.env.NODE_ENV !== 'development' ? `/micro-apps/${name}/` : `/`;
return config;
};
module.exports = overrideOutput;
c. less配置
const addLessLoader = require('customize-cra-less-loader');
addLessLoader({
cssLoaderOptions: { sourceMap: true },
lessLoaderOptions: { lessOptions: { strictMath: false, javascriptEnabled: true } },
}),
d. 优化配置
const overrideOptimization = () => (config) => {
//runtimeChunk :可以为每个入口添加一个只含有 runtime 的额外 chunk。形如import('abc').then(res=>{})这种异步加载的代码,在webpack中即为运行时代码。可以将这些代码单独创建一个chunk。可选值 true 或 'multiple',object(内只含name属性),false(默认值是 false:每个入口 chunk 中直接嵌入 runtime)。
config.optimization.runtimeChunk = false;
//CommonsChunkPlugin : 最初,chunks(以及内部导入的模块)是通过内部 webpack 图谱中的父子关系关联的。CommonsChunkPlugin 曾被用来避免他们之间的重复依赖.
//SplitChunksPlugin : 从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 SplitChunksPlugin ,用于代码的分割,打包拆分,这是一个内置的插件,无需额外引入,直接在optimization.splitChunks中书写配置即可。不仅可以提取公共的文件和库,还可以提取按需加载的文件.含有默认配置.
//默认配置的大概意思是:默认只对按需引入的模块进行代码分割;来自 node_modules 的模块,或被引用两次及以上的模块,才会做代码分割;被分割的模块必须大于30kb(代码压缩前);按需加载时,并行的请求数必须小于或等于5;初始页加载时,并行的请求数必须小于或等于3;
//splitChunks : 代表 SplitChunksPlugin 的默认行为。
//cacheGroups: 缓存组可以继承和/或覆盖来自 splitChunks.* 的任何选项。但是 test、priority 和 reuseExistingChunk 只能在缓存组级别上进行配置。将它们设置为 false以禁用任何默认缓存组。
config.optimization.splitChunks = {
cacheGroups: {
default: false,
styles: {
name: 'styles',
type: 'css/mini-extract',
//chunks: 是指交给webpack处理的文件,例如:js/css/img文件,通过import的方式引入的模块或文件都可以称之为"chunks"。可选值 initial(表示入口文件中非动态引入的模块),all(表示所有模块),async (表示异步引入的模块)
chunks: 'all',
enforce: true,
},
},
};
return config;
};
module.exports = overrideOptimization;
e. css打包
const path = require('path');
const { name } = require(path.join(process.cwd(), './package.json'));
//基于 webpack v5 的新特性构建,会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const filterWebpackPlugin = (plugins, pluginName) => plugins.filter((plugin) => plugin.constructor.name !== pluginName);
const findIndexWebpackPlugin = (plugins, pluginName) => plugins.findIndex((plugin) => plugin.constructor.name === pluginName);
const overrideMiniCssExtractPlugin = () => (config) => {
if (process.env.NODE_ENV === 'development') {
return config;
}
//找到替换
const index = findIndexWebpackPlugin(config.plugins, 'MiniCssExtractPlugin');
const plugins = filterWebpackPlugin(config.plugins, 'MiniCssExtractPlugin');
const replacePlugin = new MiniCssExtractPlugin({ filename: `static/css/${name}.css`, ignoreOrder: true });
if (index > -1) {
plugins.splice(index, 0, replacePlugin);
} else {
plugins.push(replacePlugin);
}
config.plugins = plugins;
return config;
};
module.exports = overrideMiniCssExtractPlugin;
f. 变量替换
const findWebpackPlugin = (plugins, pluginName) => plugins.find(plugin => plugin.constructor.name === pluginName);
const overrideProcessEnv = value => config => {
//DefinePlugin : 允许在 编译时 将你代码中的变量替换为其他值或表达式。
const plugin = findWebpackPlugin(config.plugins, 'DefinePlugin');
const processEnv = plugin.definitions['process.env'] || {};
plugin.definitions['process.env'] = {
...processEnv,
...value
};
return config;
};
module.exports = overrideProcessEnv;
//使用:由于这个插件会直接替换文本,因此提供的值必须在字符串本身中再包含一个 实际的引号 。通常,可以使用类似 '"production"' 这样的替换引号,或者直接用 JSON.stringify('production')。
overrideProcessEnv({ ROUTE_PERFIX: JSON.stringify('/')})
g. HTML 文件的创建
//InterpolateHtmlPlugin : 这个插件是配合html-webpack-plugin一起使用的,允许你在index.html中使用变量
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
//HtmlWebpackPlugin : 将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。
const HtmlWebpackPlugin = require('html-webpack-plugin');
const findIndexWebpackPlugin = (plugins, pluginName) => plugins.findIndex((plugin) => plugin.constructor.name === pluginName);
const overrideHTMLPlugin =
(raw = {}) =>
(config) => {
const index = findIndexWebpackPlugin(config.plugins, 'InterpolateHtmlPlugin');
config.plugins.splice(index, 0, new InterpolateHtmlPlugin(HtmlWebpackPlugin, raw));
return config;
};
module.exports = overrideHTMLPlugin;