webpack 的底层配置项resolve主要和模块解析的路径相关,常见的例如mainFiles ,extensions等node
配置模块依赖别名,常见的@解析到src文件夹,path.resolve自己是用来构造绝对路径的,因此@总能解析到src目录的路径react
module.exports = { resolve: {alias: { '@': path.resolve(__dirname, './src'), }, }, };复制代码
引入模块必须添加拓展名,默认是falsewebpack
配置文件依赖后缀名git
使用resolve.extensions能够配置文件的默认后缀名,默认是['.wasm', '.mjs', '.js', '.json']。当省略文件后缀名时,webpack 会尝试对文件名依次添加后缀名并解析,若是找到相关后缀的文件就中止解析。例如import "./data",那么 webpack 首先会去找文件夹是否存在./data.wasm的文件,找不到就换下一个后缀名./data.mjs,就这样依次解析,若是最后都找不到就会报错。github
须要注意的是默认的配置项不要删除,不然会发生错误,如今在默认配置的基础上加上jsx,即:web
module.exports = { resolve: {extensions: ['.wasm', '.mjs', '.js', '.json', 'jsx'], }, };复制代码
下面是 CRA 内置的解析顺序是这样的:npm
const moduleFileExtensions = [ 'web.mjs', 'mjs', 'web.js', 'js', 'web.ts', 'ts', 'web.tsx', 'tsx', 'json', 'web.jsx', 'jsx', ];复制代码
解析目录时要使用的文件名,默认是['index'],我在 webpack V4.44.1 的版本使用中发现单纯使用这个配置项并不会让 webpack 去自动解析文件夹下的index命名的文件,而后我在 stackoverflow 上发现了这个问题的回答 —— webpack can't find module if file named jsx,对于从 webpack 4.36.1 起,还须要在babel-loader中去配置rule.resolve.extensions,而且这个配置项是决定性的,必须加上rule.resolve.extensions的配置才会让 webpack 自动解析文件夹的index文件,而且".js"也不能省略,不然 react fast refresh 会报错。json
module.exports = { module: {rules: [ {test: /\.m?jsx?$/, exclude: /(node_modules)/, use: { loader: 'babel-loader', options: {presets: [ ['@babel/preset-env', { modules: false, }, ], ['@babel/preset-react'], ],plugins: [ '@babel/plugin-proposal-class-properties', isDevelopment && require.resolve('react-refresh/babel'), ].filter(Boolean), }, },resolve: { extensions: ['.js', '.jsx'] }, //必须加上这个配置 }, ], }, };复制代码
resolve.mainFields针对的是使用第三方库的代码如何进行解析,由于 JS 能够编写在浏览器中使用的代码,也能够编写使用在 nodejs 中的代码,或者一些通用的在服务端和浏览器均可以使用的代码。有的第三方库会针对不一样的环境提供几份打包代码放在一块儿打包,它们会在package.json文件中指定不一样环境代码的入口,例如:浏览器
{ "browser": "build/upstream.js", "module": "index"}复制代码
通常状况下,在搭建项目的时候,会经过 webpack 的配置项 target来指定 webpack 去指定当前项目运行在什么样的环境中,例如target: 'node'指定当前代码最终运行在 nodejs 环境下。具体见 —— target 。babel
当 webpack 的target属性设置成 webworker, web 或者没有指定的时候,那么mainFields的默认值就是['browser', 'module', 'main'],也就是 webpack 会最优先选择browser属性做为入口去解析第三方库的代码,对应上文说的package.json里面提供的"browser"属性的字段值。
而对于其它指定的target的属性值,例如node等,mainFields的默认值都是['module', 'main']。
告诉 webpack 解析模块时应该搜索的目录,默认是['node_modules']。webpack 经过路径解析解析模块的时候会首先查找项目根目录的./node_modules文件夹去寻找模块,若是找不到就往上一级目录 ../node_modules 中去找。
有时候这个配置比alias还简洁,比方说对于项目中封装通用业务组件库位于src/components下面,而后经过resolve.modules配置模块解析规则以下
module.exports = { resolve: {modules: [path.resolve(__dirname, './src/components'), 'node_modules'], }, };复制代码
这时候在编写页面的时候,若是import一个src/components下里面的组件,就不用带任何路径前缀直接写文件夹就好了,nice!不过这时候的弊端就是若是你的组件和第三方库的组件同名,就会把第三方库的组件覆盖掉了。
import { Button } from 'Button/index.jsx';复制代码
这个配置加上上文提到的rule.resolve.extensions,结合在一块儿就是神器,对于src/components的组件,例如src/components/Button,直接一句话就搞定,webpack 会自动查找src/components/Button文件夹下的index文件。
import { Button } from 'Button';复制代码
定义解析模块过程当中使用的插件,经常使用的应该是pnp-webpack-plugin。这个理要了解一下yarn pnp,简单来讲Plug'n'Play是替代node_modules依赖机制的方案,对于一个简单项目来讲,若是使用 pnp 替代 npm 的机制,能够经过在package.json中配置便可,对于 webpack 项目可使用插件来支持 pnp 的模块解析机制。例如,CRS 内部就是使用了pnp-webpack-plugin这个插件。
yarn add pnp-webpack-plugin -D复制代码
const PnpWebpackPlugin = require('pnp-webpack-plugin');module.exports = { resolve: {plugins: [PnpWebpackPlugin], }, resolveLoader: {plugins: [PnpWebpackPlugin.moduleLoader(module)], }, };复制代码
CRA 还使用了一个插件,是react-dev-utils/ModuleScopePlugin,这个插件的做用是阻止项目内部从src或者node_modules之外的地方引入模块,由于这一般会引发混乱。通常来讲项目代码都会放在src中,通常也不会瞎搞随便引用外面的文件夹。
resolveLoader的配置项和resolve相同,不过resolveLoader只用于解析特定的 loader 模块,例如resolveLoader.moduleExtensions默认是['-loader'],也就是解析 loader 的时候,默认会自动添加-loader的后缀名。
module.rule.resolve在上文提到过,也就是在解析特定类型的模块时使用的解析规则,如上文所说,它对于解析index命名的模块是必须配置的项。
也可使用上述的resolve的其余配置项,这些配置项会和顶层的resolve配置项进行合并。