开发环境

基于 Webpack 的 Web 应用构建与打包基础

开发环境

题注:本文是 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

alias: import “xyz” import “xyz/file.js”
{ xyz: “/some/dir” } /some/dir/index.js /some/dir/file.js
{ xyz$: “/some/dir” } /some/dir/index.js /abc/node_modules/xyz/file.js
{ xyz: “./dir” } /abc/dir/index.js /abc/dir/file.js

如前文介绍,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/*"]
  }
}
上一页
下一页