create-react-app綜合問題

發表於2019-04-04

一、 快速開始:

  • 全域性安裝腳手架:
npm install -g create-react-app複製程式碼複製程式碼
  • 通過腳手架搭建專案:
  <專案名稱>複製程式碼複製程式碼
  • 開始專案:
cd <專案名>npm run start複製程式碼複製程式碼

二、 檢視專案 package.json 資訊 

2.1 package.json 一覽

{
  ......
  "homepage": ".",
  "dependencies": {
    "react": "^16.4.0",
    "react-dom": "^16.4.0",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}
複製程式碼

2.2 可用指令碼命令說明: 

首先說明:通過npm run 執行下面命令實際上是執行 node_modules/react-srcipt/script 下對應的指令碼檔案; npm run start: 開始專案,執行專案後可通過 http://localhost:3000 訪問專案; npm run build: 專案打包,在生產環境中編譯程式碼,並放在build目錄中;所有程式碼將被正確打包,並進行優化、壓縮同時使用hash重新命名檔案;執行該命令前需要在 package.json 中新增條配置"homepage": "."(上面配置檔案已給出), 同時build後的專案需要在伺服器下才能訪問;否則開啟的將是空白頁面; npm run test: 互動監視模式下啟動測試執行程式; npm run eject: 將隱藏的配置匯出;需要知道的是create-react-app腳手架本質上是使用react-scripts進行配置專案,所有配置檔案資訊都被隱藏起來(node_modules/react-scripts);當需要手動修改擴充套件webpack配置時有時就需要將隱藏的配置暴露出來;特別需要注意的是該操作是一個單向操作,一旦使用eject,那麼就不能恢復了(再次將配置隱藏);


四、 新增對 less 的支援

4.1 方法一:暴露配置並進行修改

  • 暴露配置檔案:
npm run eject說明: 執行eject指令碼後,專案下會新增或對部分配置檔案進行修改;專案下 script 目錄存放著指令碼檔案, config 目錄下存放著配置檔案複製程式碼
  • 下載安裝依賴:less-loader less
npm install less-loader less -dev複製程式碼
  • 修改 config 目錄下的webpack配置檔案:
    • 需同時修改下面的兩個檔案:
    • 開發環境下的配置檔案:webpack.config.dev.js
    • 生產環境下的配置檔案:webpack.config.prod.js
    • 兩個檔案的修改內容相同,對應修改內容如下(三處需要進行修改)
複製程式碼

{
+   test: /\.(css|less)$/,
    use: [
        require.resolve('style-loader'),
        {
            loader: require.resolve('css-loader'),
            options: {
+           importLoaders: 2,
        },
        },
        { .... },
+       {
+         loader: require.resolve('less-loader'),
+       }
    ],
}
複製程式碼複製程式碼

4.2 方法二: 使用 react-app-rewired 對 webpack 進行自定義配置(覆蓋或新增)

4.2.1 react-app-rewired 老版本配置方法

react-app-rewired 的使用

  • 安裝 react-app-rewired 外掛
npm install react-app-rewired --save-dev

修改 package.json 中的指令碼命令:修改如下
  "scripts": {
+   "start": "react-app-rewired start",
+   "build": "react-app-rewired build",
+   "test": "react-app-rewired test --env=jsdom",
+   "eject": "react-app-rewired eject"
  }
複製程式碼
  • 在專案根目錄下(和 package.json 同級)新建配置檔案 config-overrides.js ,並新增如下內容
module.exports = function override(config, env) {  // 在這裡新增配置  return config;}複製程式碼


修改配置檔案 config-overrides.js 使得專案能夠支援 less

    • 安裝依賴包 react-app-rewire-less,通過該依賴包來實現對 less 的支援:
# 說明: 這裡不再需要額外單獨安裝依賴包:less-loader  lessnpm install react-app-rewire-less --save複製程式碼
  • 修改 config-overrides.js 配置檔案
  • + const rewireLess = require('react-app-rewire-less');
    module.exports = function override(config, env) {
    +  // 只需要一條配置資訊即可實現對less的支援
    +  config = rewireLess(config, env);
       return config;
    }
    複製程式碼

4.2.2 react-app-rewired 新版本配置方法( >=2.1.0 )

react-app-rewired 的使用: 使用上和舊版本基本一樣只是在配置上需要額外通過 customize-cra 外掛來實現


  • 安裝 react-app-rewired customize-cra 外掛
複製程式碼
  1. npm install react-app-rewired customize-cra --save-dev


  • 修改 package.json 中的指令碼命令:修改如下
複製程式碼

"scripts": {
+   "start": "react-app-rewired start",
+   "build": "react-app-rewired build",
+   "test": "react-app-rewired test --env=jsdom",
+   "eject": "react-app-rewired eject"
  }

複製程式碼
  • 在專案根目錄下(和 package.json 同級)新建配置檔案 config-overrides.js ,並新增如下內容
複製程式碼

const { override } = require('customize-cra');module.exports = override();複製程式碼

修改配置檔案 config-overrides.js 使得專案能夠支援 less

  • 安裝依賴: less less-loader
複製程式碼
  1. npm install less less-loader --save-dev
  • 修改 config-overrides.js 配置檔案: addLessLoader
複製程式碼

+ const { override, addLessLoader } = require('customize-cra');
module.exports = override(
+  addLessLoader({
+    strictMath: true,
+    noIeCompat: true
+  })
);
複製程式碼

五、 在 create-react-app 中使用Antd

安裝 antd 依賴包:
npm install antd --save
複製程式碼
5.1 方法一: 直接匯入所有樣式, 並引用相應元件
引入 antd 元件之前需要先引入 antd 樣式( 在專案入口引入所有樣式 ):
import antd/dist/antd.css
複製程式碼
在專案中引入 antd 元件

import { Button } from 'antd';複製程式碼

5.2 方法二: 按需載入

  • 上面引入元件和樣式的方式,會一次性載入所有樣式並引入元件中的所有相應模組;
  • 這種引入方式將會影響到應用的網路效能;
  • 相應的就需要改變引入元件和樣式的方式,實現樣式和元件的按需載入;
  • 下面將介紹三種按需載入元件樣式的方法:


5.2.1 引入獨立的元件和樣式

import Button from 'antd/lib/button';i
mport 'antd/lib/button/style';

// 或者通過import antd/lib/button/style/css 進行載入樣式複製程式碼

5.2.2 通過暴露配置並使用 babel-plugin-import 外掛實現按需載入

  • babel-plugin-import 是一個用於按需載入元件程式碼和樣式的 babel 外掛

    • 暴露配置

npm run eject

安裝外掛:
npm install babel-plugin-import --save-dev
複製程式碼
修改 package.json
"babel": {
  "presets": [
    "react-app"
  ],
  "plugins": [
+   ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }]
  ]
},

複製程式碼
  • 配置完後可直接匯入 antd 的元件,不再需要另外引入css樣式;
複製程式碼
  1. import { Button } from 'antd';

5.2.2 react-app-rewired + babel-plugin-import 實現按需載入(官網推薦)

react-app-rewired 老版本配置方法
  • babel-plugin-import 是一個用於按需載入元件程式碼和樣式的 babel 外掛;
  •  react-app-rewired 的使用在第四節已經有了詳細的描述這裡不在贅述;
  • 下文直接通過修改 config-overrides.js 配置來實現 antd 的按需載入 


  • 安裝依賴包:babel-plugin-import
  1. npm install babel-plugin-import --save-dev
  • 修改配置檔案 config-overrides.js: 通過 injectBabelPlugin 外掛實現 babel 的新增
複製程式碼

+ const { injectBabelPlugin } = require('react-app-rewired');
module.exports = function override(config, env) {
+  config = injectBabelPlugin(['import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }], config);
   return config;
};

複製程式碼

react-app-rewired 新版本配置方法( >=2.1.0 )
    • 新版本可以直接通過 customize-cra 的 fixBabelImports 方法實現按需載入
複製程式碼

+const { override, addLessLoader, fixBabelImports } = require('customize-cra');
module.exports = override(
 addLessLoader({
   strictMath: true,
   noIeCompat: true
 }),
+ fixBabelImports('import', { libraryName: 'antd', libraryDirectory: 'es', style: 'css' }),
);
複製程式碼

5.3 通過 react-app-rewired 擴充套件 webpack 來實現 antd 自定義主題

    • 主要通過利用了 less-loader 的 modifyVars 引數來進行主題配置
    • 下面是基於第四節中對 less 的配置的基礎上新增 modifyVars 引數來實現自定義主題的目的

5.3.1 react-app-rewired 老版本配置方法

    • 修改 config-overrides.js 配置檔案
複製程式碼

const rewireLess = require('react-app-rewire-less');
const { injectBabelPlugin } = require('react-app-rewired');
module.exports = function override(config, env) {
  // 擴充套件 webpack ==> 支援less
  config = rewireLess(config, env);
  // 配置 less-loader 載入引數
+ config = rewireLess.withLoaderOptions({modifyVars: { "@primary-color": "#1DA57A" },})(config, env);
  // antd 按需載入配置
  config = injectBabelPlugin(['import',
  { libraryName: 'antd', libraryDirectory: 'es', style: true }], config);
  return config;
}
複製程式碼

5.3.2 react-app-rewired 新版本配置方法( >=2.1.0 )

  • addLessLoader 必須新增 javascriptEnabled: true
  • fixBabelImports 實現對 antd 按需載入時需要設定 style: true


const { override, addLessLoader, fixBabelImports } = require('customize-cra');
module.exports = override(
  addLessLoader({
    strictMath: true,
    noIeCompat: true,
+   javascriptEnabled: true,
+   modifyVars: { "@primary-color": "#1DA570" }
  }),
+  fixBabelImports('import', { libraryName: 'antd', libraryDirectory: 'es', style: true }),
);

--------------------- 
複製程式碼


六、 實現對修飾器的支援: 實現對 babel 外掛的使用

安裝外掛
# 如果你的 Babel < 7.x 則安裝
 babel-plugin-transform-decorators-legacy
npm install --save-dev babel-plugin-transform-decorators-legacy
# 如果你的 Babel >= 7.x 則應該安裝
 @babel/plugin-proposal-decorators
npm install --save-dev @babel/plugin-proposal-decorators

複製程式碼

6.1 方法一: 暴露配置並進行修改

  • 假設當前 Babel >= 7.x, 如果你的 Babel < 7.x 則需要將 ["@babel/plugin-proposal-decorators", {"legacy": true}] 修改為 ["transform-decorators-legacy"]
  • 暴露配置

npm run eject複製程式碼

修改 package.json"babel": { 
 "presets": [    "react-app"  ], 
 "plugins": [
      [
    "@babel/plugin-proposal-decorators", 
    {"legacy": true}
        ]  
    ]
},複製程式碼

6.2 方法二: 使用 react-app-rewired 對 webpack 進行自定義配置(覆蓋或新增)

6.2.1 react-app-rewired 老版本配置方法

  • react-app-rewired 的使用參考第四節:
  • 修改 config-overrides.js 配置檔案

// 匯入新增babel外掛的函式
+const { injectBabelPlugin } = require('react-app-rewired');
module.exports = function override(config, env) {
+ config = injectBabelPlugin(["@babel/plugin-proposal-decorators", {"legacy": true}], config)
  return config;
};
複製程式碼

6.2.2 react-app-rewired 新版本配置方法( >=2.1.0 )

    react-app-rewired 的使用參考第四節:
     修改 config-overrides.js 配置檔案: 
    下面給出了三種配置 babel 外掛的方法,
     addBabelPlugin 和 addBabelPlugins 用法類似 useBabelRc 是允許專案使用
     .babelrc 配置檔案進行配置 

+const {
+  override, addLessLoader, fixBabelImports,
+  addBabelPlugin, addBabelPlugins, useBabelRc
+} = require('customize-cra');
module.exports = override(
 addLessLoader({
   strictMath: true,
   noIeCompat: true,
   javascriptEnabled: true,
   modifyVars: { "@primary-color": "#1DA570" }
 }),
 fixBabelImports('import', { libraryName: 'antd', libraryDirectory: 'es', style: true }),
 
+ addBabelPlugin(["@babel/plugin-proposal-decorators", {"legacy": true}]),
 
+ // ...addBabelPlugins(
+ //  ["@babel/plugin-proposal-decorators", {"legacy": true}]
+ // ),
+ // useBabelRc(),
);
 
複製程式碼複製程式碼


七、 eslint 配置

7.1 暴露配置並進行修改

    • 執行指令碼 暴露配置檔案
npm run eject複製程式碼
  • 通過修改 package.json 檔案新增對 eslint 的擴充套件配置
複製程式碼

...
"eslintConfig": {
  // 預設繼承 腳手架自帶的 eslint 配置
  "extends": "react-app",
  // 在這裡擴充套件新增配置
  "rules":{
     // 設定規則,具體看官網使用者指南下的規則文件
     "eqeqeq": "off"
  }
 }
複製程式碼

7.2 使用 react-app-rewired 對 webpack 進行自定義配置(覆蓋或新增)

7.2.1 react-app-rewired 老版本配置方法

  • react-app-rewired 的使用參考第四節:
  • 安裝依賴:
  • npm install react-app-rewired react-app-rewire-eslint --save


  • 修改 config-overrides.js 配置檔案


+ const rewireEslint = require('react-app-rewire-eslint');
module.exports = function override(config, env) {
+  config = rewireEslint(config, env);
   return config;
}
複製程式碼

  • 在根目錄下建立 .eslintrc 並自定義eslint配置
複製程式碼


{
  "rules": {
      // 設定規則,具體看官網使用者指南下的規則文件
      "eqeqeq": "off"
  }
}
複製程式碼複製程式碼

7.2.2 react-app-rewired 新版本配置方法( >=2.1.0 )

  • react-app-rewired 的使用參考第四節:
  • 修改 config-overrides.js 配置檔案: 通過 useEslintRc 啟用 .eslintrc 配置檔案

 const { override, useEslintRc } = require('customize-cra');module.exports = override(+ useEslintRc(),);複製程式碼

  • 在根目錄下建立 .eslintrc 並自定義eslint配置
複製程式碼

{
  "rules": {
      // 設定規則,具體看官網使用者指南下的規則文件
      "eqeqeq": "off"
  }
}
複製程式碼複製程式碼




const path = require('path')//配置vw// const postcssAspectRatioMini = require('postcss-aspect-ratio-mini');// const postcssPxToViewport = require('postcss-px-to-viewport');// const postcssWriteSvg = require('postcss-write-svg');// // const postcssCssnext = require('postcss-cssnext');// const postcssPresetEnv = require('postcss-preset-env');// const postcssViewportUnits = require('postcss-viewport-units');// const cssnano = require('cssnano');// module.exports = function override(config, env) {//     config.resolve.alias = {//         ...config.resolve.alias,//         '@': path.resolve(__dirname, 'src'),//     };//     return config;// };// const rewireEslint = require("react-app-rewire-eslint");

使用 customize-cra 配置  const {      useEslintRc,    override ,    addWebpackAlias,     addWebpackResolve,     addPostcssPlugins} = require('customize-cra');// function overrideEslintOptions(options) {//   // do stuff with the eslint options...//   return options;// }module.exports = {    webpack:override(
       // 配置別名        addWebpackAlias({            ["@"]: path.resolve(__dirname, 'src'),        }),
        // 配置使用viewport (vw) 外掛 -- start        addPostcssPlugins([require('postcss-flexbugs-fixes'),        require('postcss-preset-env')({            autoprefixer: {                flexbox: 'no-2009',            },            stage: 3,        }),        require('postcss-aspect-ratio-mini')({}),        require('postcss-px-to-viewport')({            viewportWidth: 750, // (Number) The width of the viewport.            viewportHeight: 1334, // (Number) The height of the viewport.            unitPrecision: 3, // (Number) The decimal numbers to allow the REM units to grow to.            viewportUnit: 'vw', // (String) Expected units.            selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.            minPixelValue: 1, // (Number) Set the minimum pixel value to replace.            mediaQuery: false // (Boolean) Allow px to be converted in media queries.        }),        require('postcss-write-svg')({            utf8: false        }),        require('postcss-viewport-units')({}),        require('cssnano')({            preset: "advanced",            autoprefixer: false,            "postcss-zindex": false        })]),
        // 配置使用viewport (vw) 外掛 -- start        // 啟用eslint
        //useEslintRc(),    ),    devServer: function(configFunction) {        // Return the replacement function for create-react-app to use to generate the Webpack        // Development Server config. "configFunction" is the function that would normally have        // been used to generate the Webpack Development server config - you can use it to create        // a starting configuration to then modify instead of having to create a config from scratch.        return function(proxy, allowedHost) {          // Create the default config by calling configFunction with the proxy/allowedHost parameters          const config = configFunction(proxy, allowedHost);               // Change the https certificate options to match your certificate, using the .env file to          // set the file paths & passphrase.          /* const fs = require('fs');          config.https = {            key: fs.readFileSync(process.env.REACT_HTTPS_KEY, 'utf8'),            cert: fs.readFileSync(process.env.REACT_HTTPS_CERT, 'utf8'),            ca: fs.readFileSync(process.env.REACT_HTTPS_CA, 'utf8'),            passphrase: process.env.REACT_HTTPS_PASS          }; */           /*  config.proxy = {                "/api": {                   "target": "http://lemonof.com:82",                   "pathRewrite": {"^/api" : ""}                }            } */          // Return your customised Webpack Development Server config.          return config;        };      },}複製程式碼



// 使用普通 react-app-rewire-postcs  配置viewport

const path = require('path')//配置vw// const postcssAspectRatioMini = require('postcss-aspect-ratio-mini');// const postcssPxToViewport = require('postcss-px-to-viewport');// const postcssWriteSvg = require('postcss-write-svg');// // const postcssCssnext = require('postcss-cssnext');// const postcssPresetEnv = require('postcss-preset-env');// const postcssViewportUnits = require('postcss-viewport-units');// const cssnano = require('cssnano');// module.exports = function override(config, env) {//     config.resolve.alias = {//         ...config.resolve.alias,//         '@': path.resolve(__dirname, 'src'),//     };//     return config;// };// const rewireEslint = require("react-app-rewire-eslint");const {      useEslintRc,    override ,    addWebpackAlias,     addWebpackResolve,     addPostcssPlugins} = require('customize-cra');// function overrideEslintOptions(options) {//   // do stuff with the eslint options...//   return options;// }module.exports = {        webpack: function(config, env) {
        // 配置別名        config.resolve.alias = {            ...config.resolve.alias,            '@': path.resolve(__dirname, 'src'),        };

       // viewport(開始) ---start        require('react-app-rewire-postcss')(config, {            plugins: loader => [                require('postcss-flexbugs-fixes'),                require('postcss-preset-env')({                    autoprefixer: {                        flexbox: 'no-2009',                    },                    stage: 3,                }),                require('postcss-aspect-ratio-mini')({}),                require('postcss-px-to-viewport')({                    viewportWidth: 750, // (Number) The width of the viewport.                    viewportHeight: 1334, // (Number) The height of the viewport.                    unitPrecision: 3, // (Number) The decimal numbers to allow the REM units to grow to.                    viewportUnit: 'vw', // (String) Expected units.                    selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.                    minPixelValue: 1, // (Number) Set the minimum pixel value to replace.                    mediaQuery: false // (Boolean) Allow px to be converted in media queries.                }),                require('postcss-write-svg')({                    utf8: false                }),                require('postcss-viewport-units')({}),                require('cssnano')({                    preset: "advanced",                    autoprefixer: false,                    "postcss-zindex": false                })            ]        });
       // viewport(開始) ---end        // config = rewireEslint(config, env, overrideEslintOptions);        return config;    },    devServer: function(configFunction) {        // Return the replacement function for create-react-app to use to generate the Webpack        // Development Server config. "configFunction" is the function that would normally have        // been used to generate the Webpack Development server config - you can use it to create        // a starting configuration to then modify instead of having to create a config from scratch.        return function(proxy, allowedHost) {          // Create the default config by calling configFunction with the proxy/allowedHost parameters          const config = configFunction(proxy, allowedHost);               // Change the https certificate options to match your certificate, using the .env file to          // set the file paths & passphrase.          /* const fs = require('fs');          config.https = {            key: fs.readFileSync(process.env.REACT_HTTPS_KEY, 'utf8'),            cert: fs.readFileSync(process.env.REACT_HTTPS_CERT, 'utf8'),            ca: fs.readFileSync(process.env.REACT_HTTPS_CA, 'utf8'),            passphrase: process.env.REACT_HTTPS_PASS          }; */           /*  config.proxy = {                "/api": {                   "target": "http://lemonof.com:82",                   "pathRewrite": {"^/api" : ""}                }            } */          // Return your customised Webpack Development Server config.          return config;        };      },}// webpack: function(config, env) {//     config.resolve.alias = {//         ...config.resolve.alias,//         '@': path.resolve(__dirname, 'src'),//     };//     require('react-app-rewire-postcss')(config, {//         plugins: loader => [//             require('postcss-flexbugs-fixes'),//             require('postcss-preset-env')({//                 autoprefixer: {//                     flexbox: 'no-2009',//                 },//                 stage: 3,//             }),//             require('postcss-aspect-ratio-mini')({}),//             require('postcss-px-to-viewport')({//                 viewportWidth: 750, // (Number) The width of the viewport.//                 viewportHeight: 1334, // (Number) The height of the viewport.//                 unitPrecision: 3, // (Number) The decimal numbers to allow the REM units to grow to.//                 viewportUnit: 'vw', // (String) Expected units.//                 selectorBlackList: ['.ignore', '.hairlines'], // (Array) The selectors to ignore and leave as px.//                 minPixelValue: 1, // (Number) Set the minimum pixel value to replace.//                 mediaQuery: false // (Boolean) Allow px to be converted in media queries.//             }),//             require('postcss-write-svg')({//                 utf8: false//             }),//             require('postcss-viewport-units')({}),//             require('cssnano')({//                 preset: "advanced",//                 autoprefixer: false,//                 "postcss-zindex": false//             })//         ]//     });//     // config = rewireEslint(config, env, overrideEslintOptions);//     useEslintRc();//     return config;// },複製程式碼


相關文章