react工程化搭建

262 阅读3分钟

1、项目创建

// 1、安装脚手架 建议使用淘宝镜像源(https://registry.npmmirror.com),可安装nrm(npm 源管理器,允许你快速地在 npm源间切换)管理镜像源
npm install -g create-react-app

// 2、创建项目 (ts)
create-react-app my-react-ts-app --template typescript

2、安装yarn

npm install -g yarn

3、配置eslint和Prettier

3.1、安装依赖

这里同时使用eslint和Prettier来统一代码风格,由于create react-app已经安装了eslint,所以我们需要安装Prettier

//根据 Prettier官方建议,Prettier版本升级之后可能会有风格变化,故应当锁定 Prettier 的版本号:
yarn add prettier --save-dev --save-exact

同时使用eslint和Prettier会存在冲突,因此使用eslint-plugin-prettiereslint-config-prettier两个依赖来解决冲突,其中:

  • eslint-plugin-prettier 将 Prettier 的规则设置到 ESLint 的规则中。
  • eslint-config-prettier 关闭 ESLint 中与 Prettier 中会发生冲突的规则。

最后形成优先级:Prettier 配置规则 > ESLint 配置规则

//安装eslint-plugin-prettier、eslint-config-prettier
yarn add eslint-config-prettier eslint-plugin-prettier --save-dev

3.2、配置文件

删除package.json中的eslintConfig属性,在根目录下新建.eslintrc.js(与 package.json 文件同级)并添加如下代码

module.exports = {
  extends: ["react-app", "plugin:prettier/recommended"],
  rules: {
    // allow debugger during development
    "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
    "no-console": 0,
    "prettier/prettier": [
      "error",
      {
        singleQuote: false, //使用单引号
        trailingComma: "all", //有效的尾随逗号(对象、数组等)
        bracketSameLine: true,
        endOfLine: "auto",
      },
    ],
    "react/self-closing-comp": ["error"], // 自动闭合标签
  },
};

注意:ESLint 的配置文件,可以是: .eslintrc.js、.eslintrc.cjs、.eslintrc.yaml、.eslintrc.yml、.eslintrc.json、 .eslintrc(已弃用)或者 package.json(第一种方法),优先级依次递减,层叠配置使用离要检测的文件最近的 .eslintrc 文件作为最高优先级,然后才是父目录里的配置文件,以此类推。

在根目录下新建.prettierrc.js(与 package.json 文件同级)并添加如下代码

module.exports = {
  singleQuote: false, //使用单引号
  trailingComma: "all", //有效的尾随逗号(对象、数组等)
  bracketSameLine: true,
};

在根目录下新建.prettierignore(与 package.json 文件同级)并添加如下代码

# Ignore artifacts:
build
config
node_modules
public
README.md
package.json
yarn.lock

3.3、 运行项目时增加风格验证

在package.json中script下添加如下代码:

"format": "prettier --write src"**/*.+(js|jsx|json|css|md)""

注意: 此处的src表示只使用Prettier格式src下文件代码 在终端执行: yarn format 就可以安装Prettier规则去格式化代码风格

安装concurrently,可以在运行 yarn start同时运行 yarn format

yarn add concurrently

修改package.json中script,最终结果:

"build": "react-scripts build",
"test": "react-scripts test",
"format": "prettier --write src\"**/*.+(js|jsx|json|css|md)\"",
"start": "concurrently  \"yarn format\" \"yarn dev\"",
"dev": "react-scripts start"

4、使用craco

使用craco可以在不运行npm run eject 下配置webpack

安装
yarn add @craco/craco
// 或者
npm install @craco/craco --save
修改package.json
"scripts": {
    "build": "craco build",
    "test": "craco test",
    "format": "prettier --write src\"**/*.+(js|jsx|json|css|md)\"",
    "start": "concurrently  \"yarn format\" \"yarn dev\"",
    "dev": "craco start"
  },
安装依赖
yarn add compression-webpack-plugin uglifyjs-webpack-plugin simple-progress-webpack-plugin craco-less
在项目根目录下创建craco.config.js文件
const CompressionWebpackPlugin = require("compression-webpack-plugin");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const SimpleProgressWebpackPlugin = require("simple-progress-webpack-plugin");
const CracoLessPlugin = require("craco-less");
const { loaderByName } = require("@craco/craco");
const path = require("path");
// 是否是生产环境
const isProduction = process.env.NODE_ENV === "production";

const commonPlugins = [
  {
    plugin: CracoLessPlugin,
    options: {
      lessLoaderOptions: {
        lessOptions: {
          modifyVars: {
            "@primary-color": "#00A2FF",
            "@link-color": "#00A2FF",
          },
          javascriptEnabled: true,
        },
      },
      modifyLessModuleRule: (lessModuleRule, context) => {
        lessModuleRule.test = /\.less$/;
        lessModuleRule.exclude = /node_modules/;
        const cssLoader = lessModuleRule.use.find(loaderByName("css-loader"));
        cssLoader.options.modules = {
          exportLocalsConvention: "camelCase",
          localIdentName: "[local]_[hash:base64:5]",
        };
        return lessModuleRule;
      },
      modifyLessRule: (lessRule, context) => {
        lessRule.test = /\.less$/;
        lessRule.include = /node_modules/;
        lessRule.exclude = undefined;

        return lessRule;
      },
    },
  },
];
const productionPlugins = [
  // 打包进度
  new SimpleProgressWebpackPlugin(),
  // 打压缩包
  new CompressionWebpackPlugin({
    filename: "[path].gz[query]", // 目标资源名称。[file] 会被替换成原资源。[path] 会被替换成原资源路径,[query] 替换成原查询字符串
    algorithm: "gzip", // 算法
    test: new RegExp("\\.(js|css)$"), // 压缩 js 与 css
    threshold: 10240, // 只处理比这个值大的资源。按字节计算
    minRatio: 0.8, // 只有压缩率比这个值小的资源才会被处理
  }),
  // 压缩ES6
  new UglifyJsPlugin({
    parallel: true,
    uglifyOptions: {
      // 在UglifyJs删除没有用到的代码时不输出警告
      warnings: false,
      // debug false
      output: {
        comments: false,
        beautify: false,
        // debug true
      },
      compress: {
        // 删除所有的 `console` 语句
        // 还可以兼容ie浏览器
        drop_console: isProduction ? true : false,
        // 内嵌定义了但是只用到一次的变量
        collapse_vars: true,
        // 提取出出现多次但是没有定义成变量去引用的静态值
        reduce_vars: true,
      },
    },
  }),
];
const devPlugins = [];

module.exports = {
  webpack: {
    // 别名
    alias: {
      "@": path.resolve("src"),
    },
  },
  plugins: isProduction
    ? [...productionPlugins, ...commonPlugins]
    : [...devPlugins, ...commonPlugins],
  // 代理
  devServer: {
    proxy: {
      "/api": {
        target: "http://localhost:3001",
        changeOrigin: true,
        pathRewrite: {
          "^/api": "/api",
        },
      },
    },
  },
};


项目地址:github.com/hanguoliang…