覆盖webpack配置

  • react-app-rewired
  • @craco/craco

    prettier+eslint

  • 安装

    1. yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-react --dev
    1. yarn add prettier eslint-config-prettier eslint-plugin-prettier --dev
  • 配置

根目录下新建 .eslintrc.js

  1. module.exports = {
  2. env: {
  3. browser: true,
  4. node: true,
  5. },
  6. parser: "@typescript-eslint/parser", // 指定ESLint解析器
  7. extends: [
  8. "plugin:react/recommended", // 使用来自 @eslint-plugin-react 的推荐规则
  9. "plugin:@typescript-eslint/recommended", // 使用来自@typescript-eslint/eslint-plugin的推荐规则
  10. "prettier/@typescript-eslint", // 使用 ESLint -config-prettier 禁用来自@typescript-eslint/ ESLint 与 prettier 冲突的 ESLint 规则
  11. "plugin:prettier/recommended",
  12. ],
  13. parserOptions: {
  14. ecmaVersion: 2018, // 允许解析最新的 ECMAScript 特性
  15. sourceType: "module", // 允许使用 import
  16. ecmaFeatures: {
  17. jsx: true, // 允许对JSX进行解析
  18. },
  19. },
  20. rules: {
  21. // 自定义规则
  22. "no-console": process.env.NODE_ENV === "production" ? "error" : "off",
  23. "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
  24. endOfLine: 0,
  25. "no-unused-vars": 0,
  26. "no-useless-escape": 0, //忽略转义字符验证
  27. },
  28. settings: {
  29. react: {
  30. version: "detect", // 告诉 eslint-plugin-react 自动检测 React 的版本
  31. },
  32. },
  33. globals: {
  34. AMap: true,
  35. },
  36. };

根目录新建 .prettierrc.js

  1. module.exports = {
  2. eslintIntegration: true,
  3. singleQuote: false,
  4. semi: true,
  5. printWidth: 200,
  6. };

根目录新建 .vscode 文件夹,下新建 setting.json

  1. {
  2. "files.autoSave": "onFocusChange",
  3. "editor.formatOnSave": true,
  4. "editor.formatOnType": true,
  5. "eslint.autoFixOnSave": true,
  6. "eslint.enable": true
  7. }

DLL

前段时间,写了一篇关于vue-cli3 的 Dllplugin 链接,个人项目是react的,所以也想修改一下。代码大部分都是一样的。提倡不要改默认配置,就是不建议要npm run eject。可以类似vue.config.js一样新建文件配置最后覆盖。其实antd ui 按需加载就提供了一个思路 customize-cra
在上面也是可以写配置文件。我以配置dllplugin为例。到时候可以自己按照实际项目扩展。
当前文件目录新建 webpack.dll.config.js

  1. const path = require('path')
  2. const webpack = require('webpack')
  3. const {
  4. CleanWebpackPlugin
  5. } = require('clean-webpack-plugin')
  6. // dll文件存放的目录
  7. const dllPath = 'public/vendor'
  8. module.exports = {
  9. entry: {
  10. // 需要提取的库文件
  11. vendor: ['react','antd','react-dom','react-redux','redux','react-router-dom','redux-thunk','axios','less-loader']
  12. },
  13. output: {
  14. path: path.join(__dirname, dllPath),
  15. filename: '[name].dll.js',
  16. // vendor.dll.js中暴露出的全局变量名
  17. // 保持与 webpack.DllPlugin 中名称一致
  18. library: '[name]_[hash]'
  19. },
  20. plugins: [
  21. // 清除之前的dll文件
  22. new CleanWebpackPlugin(),
  23. // 设置环境变量
  24. new webpack.DefinePlugin({
  25. 'process.env': {
  26. NODE_ENV: 'production'
  27. }
  28. }),
  29. // manifest.json 描述动态链接库包含了哪些内容
  30. new webpack.DllPlugin({
  31. path: path.join(__dirname, dllPath, '[name]-manifest.json'),
  32. // 保持与 output.library 中名称一致
  33. name: '[name]_[hash]',
  34. context: process.cwd()
  35. })
  36. ]
  37. }

package.json

  1. "scripts": {
  2. "start": "react-app-rewired start",
  3. + "dll": "webpack -p --progress --config ./webpack.dll.conf.js",
  4. "build": "react-app-rewired build",
  5. "test": "react-app-rewired test"
  6. },

npm run dll
在public文件夹下面生成vendor文件即可

完整配置

config-overrides.js (可以去看antd UI 官网按需加载 地址链接)。这里只是在基础上扩张webpack配置addCustomize

  1. const {
  2. override,
  3. addLessLoader,
  4. fixBabelImports,
  5. addWebpackAlias,
  6. addDecoratorsLegacy,
  7. overrideDevServer,
  8. } = require("customize-cra");
  9. const path = require("path");
  10. const webpack = require("webpack");
  11. const AddAssetHtmlPlugin = require("add-asset-html-webpack-plugin");
  12. /**
  13. * 打包进度条
  14. */
  15. const WebpackBar = require("webpackbar");
  16. /**
  17. * 生产环境去除注释
  18. */
  19. const TerserPlugin = require("terser-webpack-plugin");
  20. /**
  21. * webpack 打包分析
  22. *
  23. */
  24. const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer"); //分析插件,打包后在build/static/report.html中展示各模块所占的大小
  25. /**
  26. * 速度分析
  27. */
  28. const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
  29. const smp = new SpeedMeasurePlugin();
  30. /**
  31. * 开启gzip压缩
  32. */
  33. const productionGzipExtensions = ["js", "css", "json", "txt"];
  34. const CompressionWebpackPlugin = require("compression-webpack-plugin");
  35. /**
  36. *
  37. * 环境变量
  38. *
  39. */
  40. const ENV = process.env;
  41. /**
  42. * 开发服务配置
  43. */
  44. const devServerConfig = () => (config) => {
  45. console.log("=======>" + config.mode + "===========");
  46. config.proxy = {
  47. "/api": {
  48. target: ENV.REACT_APP_BASE_URL,
  49. changeOrigin: true,
  50. logLevel: "debug",
  51. secure: false,
  52. },
  53. };
  54. return config;
  55. };
  56. /**
  57. *
  58. * webpack-config配置
  59. *
  60. */
  61. const rewiredMap = () => (config) => {
  62. // config为所有的webpack配置
  63. config.devtool =
  64. config.mode === "development" ? "cheap-module-source-map" : false; // 生产环境关闭sourcemap关闭
  65. config.plugins.push(new WebpackBar());
  66. if (config.mode === "production") {
  67. config.plugins.push(
  68. new CompressionWebpackPlugin({
  69. test: new RegExp("\\.(" + productionGzipExtensions.join("|") + ")$"),
  70. threshold: 10240, // 对超过10k的数据压缩
  71. deleteOriginalAssets: false, // 不删除源文件
  72. }),
  73. new TerserPlugin({
  74. extractComments: true,
  75. cache: true,
  76. parallel: true,
  77. sourceMap: true, // Must be set to true if using source-maps in production
  78. terserOptions: {
  79. extractComments: "all",
  80. compress: {
  81. drop_console: true,
  82. },
  83. },
  84. }),
  85. new webpack.optimize.SplitChunksPlugin({
  86. chunks: "all",
  87. minSize: 20000,
  88. minChunks: 1,
  89. maxAsyncRequests: 5,
  90. maxInitialRequests: 3,
  91. name: true,
  92. })
  93. );
  94. }
  95. return config;
  96. };
  97. /**
  98. * dll配置,不建议生产环境使用 ,不常变化的包使用dll加快打包速度
  99. */
  100. const addCustomize = () => (config) => {
  101. if (config.mode === "development") {
  102. config.plugins.push(
  103. new webpack.DllReferencePlugin({
  104. context: process.cwd(),
  105. manifest: require("./public/vendor/vendor-manifest.json"),
  106. }),
  107. // 将 dll 注入到 生成的 html 模板中
  108. new AddAssetHtmlPlugin({
  109. // dll文件位置
  110. filepath: path.resolve(__dirname, "./public/vendor/*.js"),
  111. // dll 引用路径
  112. publicPath: "./vendor",
  113. // dll最终输出的目录
  114. outputPath: "./vendor",
  115. })
  116. );
  117. }
  118. return config;
  119. };
  120. /**
  121. * 打包分析
  122. */
  123. const analyzerConfig = () => (config) => {
  124. if (config.mode === "production") {
  125. config.plugins.push(
  126. new BundleAnalyzerPlugin({
  127. analyzerMode: "static", //输出静态报告文件report.html,而不是启动一个web服务
  128. })
  129. );
  130. }
  131. return config;
  132. };
  133. const webpackConfig = override(
  134. fixBabelImports("import", {
  135. libraryName: "antd",
  136. libraryDirectory: "es",
  137. style: "css",
  138. }),
  139. addLessLoader({
  140. lessOptions: {
  141. javascriptEnabled: true,
  142. localIdentName: "[local]--[hash:base64:5]",
  143. },
  144. }),
  145. addWebpackAlias({
  146. "@": path.resolve(__dirname, "./src"),
  147. }),
  148. (config, env) => {
  149. //修改、添加loader 配置 :
  150. // 所有的loaders规则是在config.module.rules(数组)的第二项
  151. // 即:config.module.rules[2].oneof (如果不是,具体可以打印 一下是第几项目)
  152. // 修改 less 配置 ,规则 loader 在第7项(具体可以打印配置)
  153. const loaders = config.module.rules.find((rule) =>
  154. Array.isArray(rule.oneOf)
  155. ).oneOf;
  156. loaders[7].use.push({
  157. loader: "style-resources-loader",
  158. options: {
  159. patterns: [
  160. path.resolve(__dirname, "src/styles/mixin.less"),
  161. path.resolve(__dirname, "src/styles/variables.less"),
  162. ],
  163. },
  164. });
  165. return config;
  166. },
  167. addDecoratorsLegacy(),
  168. rewiredMap(),
  169. // addCustomize(),
  170. analyzerConfig()
  171. );
  172. module.exports = {
  173. webpack: webpackConfig,
  174. devServer: overrideDevServer(devServerConfig()),
  175. };

npm run build
看能不能在打包后的文件夹中index.html中是否引用vendor文件,成功就ok了。跟vue-cli3相似。

  1. {
  2. "name": "react_antd_admin_template",
  3. "version": "1.0.0",
  4. "author": "wangchaoxu",
  5. "license": "MIT",
  6. "private": true,
  7. "scripts": {
  8. "start": "cross-env react-app-rewired start",
  9. "serve": "react-app-rewired start",
  10. "build": "cross-env react-app-rewired --max-old-space-size=4096 build ",
  11. "clear": "rimraf node_modules && rimraf yarn.lock",
  12. "test": "react-app-rewired test",
  13. "eject": "react-scripts eject",
  14. "commit": "git cz",
  15. "dll2": "webpack -p --progress --config webpack.dll.config.js",
  16. "dll": "webpack --config webpack.dll.config.js"
  17. },
  18. "dependencies": {
  19. "@testing-library/jest-dom": "^4.2.4",
  20. "@testing-library/react": "^9.5.0",
  21. "@testing-library/user-event": "^7.2.1",
  22. "@toast-ui/react-editor": "^2.1.0",
  23. "antd": "^3.17.0",
  24. "axios": "^0.19.2",
  25. "cross-env": "^7.0.3",
  26. "driver.js": "^0.9.8",
  27. "echarts": "^4.7.0",
  28. "js-cookie": "^2.2.1",
  29. "less": "^3.9.0",
  30. "less-loader": "5.0.0",
  31. "lodash-es": "^4.17.20",
  32. "nprogress": "^0.2.0",
  33. "prop-types": "^15.7.2",
  34. "react": "^16.13.1",
  35. "react-beautiful-dnd": "^13.0.0",
  36. "react-countup": "^4.3.3",
  37. "react-custom-scrollbars": "^4.2.1",
  38. "react-document-title": "^2.0.3",
  39. "react-dom": "^16.13.1",
  40. "react-draft-wysiwyg": "^1.14.5",
  41. "react-loadable": "^5.5.0",
  42. "react-redux": "^7.2.0",
  43. "react-router-dom": "^5.1.2",
  44. "react-scripts": "3.4.1",
  45. "redux": "^4.0.5",
  46. "redux-thunk": "^2.3.0",
  47. "script-loader": "^0.7.2"
  48. },
  49. "browserslist": {
  50. "production": [
  51. ">0.2%",
  52. "not dead",
  53. "not op_mini all"
  54. ],
  55. "development": [
  56. "last 1 chrome version",
  57. "last 1 firefox version",
  58. "last 1 safari version"
  59. ]
  60. },
  61. "devDependencies": {
  62. "@babel/plugin-proposal-decorators": "^7.12.12",
  63. "add-asset-html-webpack-plugin": "^3.1.3",
  64. "babel-plugin-import": "^1.13.0",
  65. "clean-webpack-plugin": "^3.0.0",
  66. "commitizen": "^4.0.3",
  67. "compression-webpack-plugin": "6.1.1",
  68. "customize-cra": "^1.0.0",
  69. "cz-conventional-changelog": "^3.0.2",
  70. "less": "^4.0.0",
  71. "less-loader": "^7.2.1",
  72. "mockjs": "^1.1.0",
  73. "react-app-rewire-css-modules": "^1.0.0",
  74. "react-app-rewire-less-modules": "^1.3.0",
  75. "react-app-rewired": "^2.1.5",
  76. "speed-measure-webpack-plugin": "^1.3.3",
  77. "style-resources-loader": "^1.4.1",
  78. "styled-components": "^5.2.1",
  79. "terser-webpack-plugin": "3.1.0",
  80. "user-agent": "^1.0.4",
  81. "webpack-bundle-analyzer": "^4.3.0",
  82. "webpack-cli": "3.3.12",
  83. "webpackbar": "^5.0.0-3"
  84. },
  85. "config": {
  86. "commitizen": {
  87. "path": "./node_modules/cz-conventional-changelog"
  88. }
  89. }
  90. }