<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          搞清楚怎樣基于 Webpack5 從 0 搭建 React開發(fā)環(huán)境-超詳細

          共 36646字,需瀏覽 74分鐘

           ·

          2021-04-06 22:37


          出處 @劉江 ,原文地址 https://juejin.cn/post/6929496472232656909


          初始化

          創(chuàng)建文件夾并進入:

          $ mkdir tristana && cd tristana

          初始化 package.json

          $ npm init

          安裝 Webpack

          $ npm install webpack webpack-cli --save-dev

          創(chuàng)建以下目錄結構、文件和內(nèi)容:

          project

          tristana
          |- package.json
          |- /dist
             |- index.html
          |- /script
             |- webpack.config.js
          |- index.html
          |- /src
             |- index.js

          src/index.js

          document.getElementById("root").append("React");

          index.html && dist/index.html

          <!DOCTYPE html>
          <html>
              <head>
                  <meta charset="utf-8" />
                  <title>tristana</title>
              </head>
              <body>
                  <script src="../src/index.js"></script>
                  <div id="root"></div>
              </body>
          </html>

          script/webpack.config.js

          module.exports = {
              mode: "development",
              entry: "./src/index.js",
          };

          package.json

          {
              // ...
              "scripts": {
                  "build""webpack --mode=development --config script/webpack.config.js"
              },
          }

          然后根目錄終端輸入:npm run build

          在瀏覽器中打開 dist 目錄下的 index.html,如果一切正常,你應該能看到以下文本:'React'

          index.html 目前放在 dist 目錄下,但它是手動創(chuàng)建的,下面會教你如何生成 index.html 而非手動編輯它。

          Webpack 核心功能

          Babel

          $ npm install @babel/cli @babel/core babel-loader @babel/preset-env --save-dev

          script/webpack.config.js

          module.exports = {
              // ...
              module: {
                  rules: [
                      {
                          test: /\.(js|jsx)$/,
                          loader: "babel-loader",
                          exclude: /node_modules/,
                      },
                  ],
              },
          };

          .babelrc

          在根目錄下添加 .babelrc 文件:

          {
              "presets": ["@babel/preset-env""@babel/preset-react"]
          }

          樣式

          $ npm install style-loader css-loader less less-loader --save-dev

          script/webpack.config.js

          module.exports = {
              // ...
              module: {
                  rules: [
                      {
                          test: /\.(css|less)$/,
                          use: [
                              {
                                  loader: "style-loader",
                              },
                              {
                                  loader: "css-loader",
                                  options: {
                                      importLoaders: 1,
                                  },
                              },
                              {
                                  loader: "less-loader",
                                  lessOptions: {
                                      javascriptEnabled: true,
                                  },
                              },
                          ],
                      },
                  ],
              },
          };

          圖片字體

          $ npm install file-loader --save-dev

          script/webpack.config.js

          module.exports = {
              // ...
              module: {
                  rules: [
                      {
                          test: /\.(png|svg|jpg|gif|jpeg)$/,
                          loader: 'file-loader'
                      },
                      {
                          test: /\.(woff|woff2|eot|ttf|otf)$/,
                          loader: 'file-loader'
                      }
                  ],
              },
          };

          HTML

          $ npm install html-webpack-plugin --save-dev

          script/webpack.config.js

          const HtmlWebpackPlugin = require('html-webpack-plugin');
          module.exports = {
              // ...
              plugins: {
                  html: new HtmlWebpackPlugin({
                      title: 'tristana',
                      template: 'public/index.html'
                  }),
              }
          };

          index.html

          <!DOCTYPE html>
          <html>
              <head>
                  <meta charset="utf-8" />
                  <title>tristana</title>
              </head>
              <body>
                  <div id="root"></div>
              </body>
          </html>

          開發(fā)服務

          $ npm install webpack-dev-server --save-dev

          script/webpack.config.js

          const path = require("path");
          const HtmlWebpackPlugin = require('html-webpack-plugin');
          module.exports = {
              // ...
              devServer: {
                  contentBase: path.resolve(__dirname, "dist"),
                  hot: true,
                  historyApiFallback: true,
                  compress: true,
              },
          };

          package.json

          {
              // ...
              "scripts": {
                  "start""webpack serve --mode=development --config script/webpack.config.js"
              },
              // ...
          }

          清理 dist

          $ npm install clean-webpack-plugin --save-dev

          script/webpack.config.js

          const { CleanWebpackPlugin } = require('clean-webpack-plugin');
          module.exports = {
              // ...
              plugins: {
                  new CleanWebpackPlugin()
              }
          };

          Tips

          由于 webpack 使用的是^5.21.2 版本,在使用該插件時,會提示clean-webpack-plugin: options.output.path not defined. Plugin disabled...,暫時還未解決。

          環(huán)境變量

          $ npm install cross-env --save-dev

          package.json

          {
              // ...
              "scripts": {
                  "start""cross-env ENV_LWD=development webpack serve  --mode=development --config script/webpack.config.js",
                  "build""cross-env ENV_LWD=production webpack --mode=production --config script/webpack.config.js"
              },
              // ...
          }

          .jsx 文件

          安裝依賴

          $ npm install @babel/preset-react react react-dom --save-dev

          .babelrc

          {
            "presets": ["@babel/preset-env""@babel/preset-react"]
          }

          src/App.jsx

          在 src 目錄下,新增 App.jsx 文件:

          import React, { Component } from "react";

          class App extends Component {
              render() {
                  return (
                      <div>
                          <h1> Hello, World! </h1>
                      </div>
                  );
              }
          }

          export default App;

          src/index.js

          import React from "react";
          import ReactDOM from "react-dom";
          import App from "./App.jsx";
          ReactDOM.render(<App />, document.getElementById("root"));

          React Router

          安裝依賴

          $ npm install react-router history --save

          src/index.js

          import React from "react";
          import ReactDOM from "react-dom";
          import { Router, Route, Link } from "react-router";
          import { createBrowserHistory } from "history";
          import App from "./App.jsx";

          const About = () => {
              return <>About</>;
          };

          ReactDOM.render(
              <Router history={createBrowserHistory()}>
                  <Route path="/" component={App} />
                  <Route path="/about" component={About} />
              </Router>,
              document.getElementById("root")
          );

          MobX

          安裝依賴

          $ npm install mobx mobx-react babel-preset-mobx --save

          .babelrc

          {
            "presets": ["@babel/preset-env""@babel/preset-react""mobx"]
          }

          src/store.js

          在 src 目錄下新建 store.js

          import { observable, action, makeObservable } from "mobx";

          class Store {

              constructor() {
                  makeObservable(this);
              }

              @observable
              count = 0;

              @action("add")
              add = () => {
                  this.count = this.count + 1;
              };

              @action("reduce")
              reduce = () => {
                  this.count = this.count - 1;
              };
          }
          export default new Store();

          index.js

          import { Provider } from "mobx-react";
          import Store from "./store";
          // ...
          ReactDOM.render(
              <Provider store={Store}>
                  <Router history={createBrowserHistory()}>
                  <Route path="/" component={App} />
                  <Route path="/about" component={About} />
                  </Router>
              </Provider>,
              document.getElementById("root")
          );

          src/App.jsx

          import React, { Component } from "react";
          import { observer, inject } from "mobx-react";

          @inject("store")
          @observer
          class App extends Component {
              render() {
                  return (
                      <div>
                          <div>{this.props.store.count}</div>
                          <button onClick={this.props.store.add}>add</button>
                          <button onClick={this.props.store.reduce}>reduce</button>
                      </div>
                  );
              }
          }

          export default App;

          Ant Design

          安裝依賴

          $ npm install antd babel-plugin-import --save

          .babelrc

          {
              // ...
              "plugins": [
                  [
                      "import",
                      {
                          "libraryName""antd",
                          "libraryDirectory""es",
                          "style"true
                      }
                  ]
              ]
          }

          src/App.jsx

          // ...
          import { DatePicker } from "antd";
          import "antd/dist/antd.css";

          @inject("store")
          @observer
          class App extends Component {
              render() {
                  return (
                      <div>
                          <DatePicker />
                      </div>
                  );
              }
          }

          export default App;

          TypeScript

          安裝依賴

          $ npm install typescript @babel/preset-typescript --save-dev

          .babelrc

          {
              "presets": [
                  // ...
                  "@babel/preset-typescript"
              ]
          }

          tsconfig.json

          在根目錄下,新增 tsconfig.json 文件:

          {
              "compilerOptions": {
                  "emitDecoratorMetadata"true,
                  "experimentalDecorators"true,
                  "target""ES5",
                  "allowSyntheticDefaultImports"true,
                  "strict"true,
                  "forceConsistentCasingInFileNames"true,
                  "allowJs"true,
                  "outDir""./dist/",
                  "esModuleInterop"true,
                  "noImplicitAny"false,
                  "sourceMap"true,
                  "module""esnext",
                  "moduleResolution""node",
                  "isolatedModules"true,
                  "importHelpers"true,
                  "lib": ["esnext""dom""dom.iterable"],
                  "skipLibCheck"true,
                  "jsx""react",
                  "typeRoots": ["node""node_modules/@types"],
                  "rootDirs": ["./src"],
                  "baseUrl""./src"
              },
              "include": ["./src/**/*"],
              "exclude": ["node_modules"]
          }

          src/App.jsx

          更換文件后綴 App.jsx -> App.tsx

          import React, { Component } from "react";
          import { observer, inject } from "mobx-react";
          import { DatePicker } from "antd";
          import "antd/dist/antd.css";

          @inject("store")
          @observer
          class App extends Component {
              props: any;
              render() {
                  return (
                      <div>
                          <DatePicker />
                          <div>{this.props.store.count}</div>
                          <button onClick={this.props.store.add}>add</button>
                          <button onClick={this.props.store.reduce}>reduce</button>
                      </div>
                  );
              }
          }

          export default App;

          代碼規(guī)范

          代碼校驗、代碼格式化、Git 提交前校驗、Vscode配置、編譯校驗

          ESLint

          安裝依賴

          $ npm install @typescript-eslint/parser eslint eslint-plugin-standard @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-promise  --save-dev

          .eslintrc.js

          在根目錄下,新增 .eslintrc.js 文件:

          module.exports = {
              extends: ["eslint:recommended""plugin:react/recommended"],
              env: {
                  browser: true,
                  commonjs: true,
                  es6: true,
              },
              globals: {
                  $: true,
                  process: true,
                  __dirname: true,
              },
              parser: "@typescript-eslint/parser",
              parserOptions: {
                  ecmaFeatures: {
                      jsx: true,
                      modules: true,
                  },
                  sourceType: "module",
                  ecmaVersion: 6,
              },
              plugins: ["react""standard""promise""@typescript-eslint"],
              settings: {
                  "import/ignore": ["node_modules"],
                  react: {
                      version: "latest",
                  },
              },
              rules: {
                  quotes: [2, "single"],
                  "no-console": 0,
                  "no-debugger": 1,
                  "no-var": 1,
                  semi: ["error""always"],
                  "no-irregular-whitespace": 0,
                  "no-trailing-spaces": 1,
                  "eol-last": 0,
                  "no-unused-vars": [
                  1,
                  {
                      vars: "all",
                      args: "after-used",
                  },
                  ],
                  "no-case-declarations": 0,
                  "no-underscore-dangle": 0,
                  "no-alert": 2,
                  "no-lone-blocks": 0,
                  "no-class-assign": 2,
                  "no-cond-assign": 2,
                  "no-const-assign": 2,
                  "no-delete-var": 2,
                  "no-dupe-keys": 2,
                  "use-isnan": 2,
                  "no-duplicate-case": 2,
                  "no-dupe-args": 2,
                  "no-empty": 2,
                  "no-func-assign": 2,
                  "no-invalid-this": 0,
                  "no-redeclare": 2,
                  "no-spaced-func": 2,
                  "no-this-before-super": 0,
                  "no-undef": 2,
                  "no-return-assign": 0,
                  "no-script-url": 2,
                  "no-use-before-define": 2,
                  "no-extra-boolean-cast": 0,
                  "no-unreachable": 1,
                  "comma-dangle": 2,
                  "no-mixed-spaces-and-tabs": 2,
                  "prefer-arrow-callback": 0,
                  "arrow-parens": 0,
                  "arrow-spacing": 0,
                  camelcase: 0,
                  "jsx-quotes": [1, "prefer-double"],
                  "react/display-name": 0,
                  "react/forbid-prop-types": [
                  2,
                  {
                      forbid: ["any"],
                  },
                  ],
                  "react/jsx-boolean-value": 0,
                  "react/jsx-closing-bracket-location": 1,
                  "react/jsx-curly-spacing": [
                  2,
                  {
                      when: "never",
                      children: true,
                  },
                  ],
                  "react/jsx-indent": ["error", 4],
                  "react/jsx-key": 2,
                  "react/jsx-no-bind": 0,
                  "react/jsx-no-duplicate-props": 2,
                  "react/jsx-no-literals": 0,
                  "react/jsx-no-undef": 1,
                  "react/jsx-pascal-case": 0,
                  "react/jsx-sort-props": 0,
                  "react/jsx-uses-react": 1,
                  "react/jsx-uses-vars": 2,
                  "react/no-danger": 0,
                  "react/no-did-mount-set-state": 0,
                  "react/no-did-update-set-state": 0,
                  "react/no-direct-mutation-state": 2,
                  "react/no-multi-comp": 0,
                  "react/no-set-state": 0,
                  "react/no-unknown-property": 2,
                  "react/prefer-es6-class": 2,
                  "react/prop-types": 0,
                  "react/react-in-jsx-scope": 2,
                  "react/self-closing-comp": 0,
                  "react/sort-comp": 0,
                  "react/no-array-index-key": 0,
                  "react/no-deprecated": 1,
                  "react/jsx-equals-spacing": 2,
              },
          };


          .eslintignore

          在根目錄下,新增 .eslintignore 文件:

          src/assets

          .vscode

          在根目錄下新增 .vscode 文件夾,然后新增 .vscode/settings.json

          {
              "eslint.validate": [
                  "javascript",
                  "javascriptreact",
                  "typescript",
                  "typescriptreact"
              ]
          }

          Perttier

          安裝依賴

          $ npm install prettier --save-dev

          prettier.config.js

          在根目錄下,新增 prettier.config.js 文件:

          module.exports = {
              // 一行最多 100 字符
              printWidth: 100,
              // 使用 4 個空格縮進
              tabWidth: 4,
              // 不使用縮進符,而使用空格
              useTabs: false,
              // 行尾需要有分號
              semi: true,
              // 使用單引號
              singleQuote: true,
              // 對象的 key 僅在必要時用引號
              quoteProps: 'as-needed',
              // jsx 不使用單引號,而使用雙引號
              jsxSingleQuote: false,
              // 末尾不需要逗號
              trailingComma: 'none',
              // 大括號內(nèi)的首尾需要空格
              bracketSpacing: true,
              // jsx 標簽的反尖括號需要換行
              jsxBracketSameLine: false,
              // 箭頭函數(shù),只有一個參數(shù)的時候,也需要括號
              arrowParens: 'avoid',
              // 每個文件格式化的范圍是文件的全部內(nèi)容
              rangeStart: 0,
              rangeEnd: Infinity,
              // 不需要寫文件開頭的 @prettier
              requirePragma: false,
              // 不需要自動在文件開頭插入 @prettier
              insertPragma: false,
              // 使用默認的折行標準
              proseWrap: 'preserve',
              // 根據(jù)顯示樣式?jīng)Q定 html 要不要折行
              htmlWhitespaceSensitivity: 'css',
              // 換行符使用 lf
              endOfLine: 'lf'
          };

          stylelint

          安裝依賴

          $ npm install stylelint stylelint-config-standard stylelint-config-prettier --save-dev

          stylelint.config.js

          在根目錄下,新增 stylelint.config.js 文件:

          module.exports = {
              extends: ['stylelint-config-standard''stylelint-config-prettier'],
              ignoreFiles: [
                  '**/*.ts',
                  '**/*.tsx',
                  '**/*.png',
                  '**/*.jpg',
                  '**/*.jpeg',
                  '**/*.gif',
                  '**/*.mp3',
                  '**/*.json'
              ],
              rules: {
                  'at-rule-no-unknown': [
                      true,
                      {
                          ignoreAtRules: ['extends''ignores']
                      }
                  ],
                  indentation: 4,
                  'number-leading-zero': null,
                  'unit-allowed-list': ['em''rem''s''px''deg''all''vh''%'],
                  'no-eol-whitespace': [
                      true,
                      {
                          ignore: 'empty-lines'
                      }
                  ],
                  'declaration-block-trailing-semicolon''always',
                  'selector-pseudo-class-no-unknown': [
                      true,
                      {
                          ignorePseudoClasses: ['global']
                      }
                  ],
                  'block-closing-brace-newline-after''always',
                  'declaration-block-semicolon-newline-after''always',
                  'no-descending-specificity': null,
                  'selector-list-comma-newline-after''always',
                  'selector-pseudo-element-colon-notation''single'
              }
          };

          lint-staged、pre-commit

          安裝依賴

          $ npm install lint-staged prettier eslint pre-commit --save-dev

          package.json

          {
              // ...
              "scripts": {
                  "lint:tsx""eslint --ext .tsx src && eslint --ext .ts src",
                  "lint:css""stylelint --aei .less .css src",
                  "precommit""lint-staged",
                  "precommit-msg""echo 'Pre-commit checks...' && exit 0"
              },
              "pre-commit": [
                  "precommit",
                  "precommit-msg"
              ],
              "lint-staged": {
                  "*.{js,jsx,ts,tsx}": [
                      "eslint --fix",
                      "prettier --write",
                      "git add"
                  ],
                  "*.{css,less}": [
                      "stylelint --fix",
                      "prettier --write",
                      "git add"
                  ]
              }
          }

          eslint-webpack-plugin

          安裝依賴

          $ npm install eslint-webpack-plugin --save-dev

          script/webpack.config.js

          const ESLintPlugin = require('eslint-webpack-plugin');
          module.exports = {
              // ...
              plugins: [new ESLintPlugin()],
          };

          總結

          搭建這個的過程,也是遇到了不少坑,收獲也是蠻多的,希望這個教程能夠幫助更多的同學,少采點坑,完整的 React 開發(fā)環(huán)境可以看這個tristana,求點贊,求關注!

          看完兩件事

          如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我兩件小事

          1.點個「在看」,讓更多人也能看到這篇內(nèi)容(點了在看」,bug -1 ??

          2.關注公眾號「前端技術江湖」,持續(xù)為你推送精選好文
          點個『在看』支持下 


          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  小泽玛利亚跟黑人三P | 色护士在线综合资源视频 | 青青操激情视频 | 精品人伦一区二区三区蜜桃网站 | 亚洲日韩精品中文字幕在线 |