题注:本文是 Webpack CheatSheet | Webpack 基础与实践清单的一部分,项目代码可以参考 fe-boilerplate | 多技术栈前端项目模板。
路径解析随着需求的迭代与功能的完善,我们的项目也会愈发庞大而复杂,目录层级结构也会不断深化;以 React 实践清单中讨论的 React 项目组织方式为例,我们常会分为 components, containers, services, apis, ducks, store, i18n 等等目录,如果全部以相对路径方式引入,可能会变成这个样子:
import React from 'react';
import { connect } from 'react-redux';
import { someConstant } from './../../config/constants';
import MyComponent from './../../../components/MyComponent';
import { myActionCreator } from './../../../ducks/someReducer';
毫无疑问,这样繁多的引用不可避免地会导致代码之间耦合度的增加,使得更难以重构或者优化。在适当地模块划分的基础上,我们希望在跨模块引用时,能够以绝对路径的方式,譬如:
import React from 'react';
import { connect } from 'react-redux';
import { someConstant } from 'Config/constants';
import MyComponent from 'Components/MyComponent';
import { myActionCreator } from 'Ducks/someReducer';
当然,我们并不提倡过度地使用绝对路径引入,对于相对关系固定的组件,还是应该优先使用相对路径方式引入。
Webpack
如前文介绍,Webpack 允许我们使用 resolve.alias
来自定义路径解析:
module.resolve = {
alias: {
Config: path.resolve(__dirname, '..', 'src', 'config'),
Components: path.resolve(__dirname, '..', 'src', 'components'),
Ducks: path.resolve(__dirname, '..', 'src', 'ducks'),
Shared: path.resolve(__dirname, '..', 'src', 'shared'),
App: path.join(__dirname, '..', 'src')
}
};
VSCode
开发工具的支持是不可避免地因素,值得高兴的是 VSCode 允许我们在 jsconfig.json
中配置解析规则,Auto-Import 这样的自动导入工具同样能识别这些规则:
{
"compilerOptions": {
"target": "es2017",
"allowSyntheticDefaultImports": false,
"baseUrl": "./",
"paths": {
"Config/*": ["src/config/*"],
"Components/*": ["src/components/*"],
"Ducks/*": ["src/ducks/*"],
"Shared/*": ["src/shared/*"],
"App/*": ["src/*"]
}
},
"exclude": ["node_modules", "dist"]
}
ESLint
ESLint 同样是前端开发不可或缺的部分,我们可以使用 eslint-import-resolver-webpack 来扩展 eslint-import 的模块解析,使用 npm 安装该模块之后进行如下配置:
---
settings:
import/resolver: webpack # take all defaults
或者指定文件名:
---
settings:
import/resolver:
webpack:
config: 'webpack.dev.config.js'
config-index: 1 # optional, take the config at index 1
对于未使用 Webpack 的项目,则可以考虑使用 eslint-import-resolver-alias:
// .eslintrc.js
module.exports = {
settings: {
'import/resolver': {
alias: {
map: [
['babel-polyfill', 'babel-polyfill/dist/polyfill.min.js'],
['helper', './utils/helper'],
['material-ui/DatePicker', '../custom/DatePicker'],
['material-ui', 'material-ui-ie10']
],
extensions: ['.ts', '.js', '.jsx', '.json']
}
}
}
};
Jest
我们可以在 package.json 中的 jest 配置项中添加 moduleNameMapper 属性:
"jest": {
"moduleNameMapper": {
"^Config(.*)$": "<rootDir>/src/config$1",
"^Components(.*)$": "<rootDir>/src/components$1",
"^Ducks(.*)$": "<rootDir>/src/ducks$1",
"^Shared(.*)$": "<rootDir>/src/shared$1",
"^App(.*)$": "<rootDir>/src$1"
}
TypeScript
TypeScript 的配置类似于 VSCode,在 tsconfig.json 的 compilerOptions 选项中添加如下配置:
{
"baseUrl": ".",
"paths": {
"c-apis/*": ["src/apis/*"],
"c-models/*": ["src/models/*"],
"c-stores/*": ["src/stores/*"],
"c-utils/*": ["src/shared/*"]
}
}