1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

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

        共 36646字,需瀏覽 74分鐘

         ·

        2021-04-06 22:37


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


        初始化

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

        $ mkdir tristana && cd tristana

        初始化 package.json

        $ npm init

        安裝 Webpack

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

        創(chuàng)建以下目錄結(jié)構(gòu)、文件和內(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

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

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

        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>

        開(kāi)發(fā)服務(wù)

        $ 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 版本,在使用該插件時(shí),會(huì)提示clean-webpack-plugin: options.output.path not defined. Plugin disabled...,暫時(shí)還未解決。

        環(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ī)范

        代碼校驗(yàn)、代碼格式化、Git 提交前校驗(yàn)、Vscode配置、編譯校驗(yàn)

        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 個(gè)空格縮進(jìn)
            tabWidth: 4,
            // 不使用縮進(jìn)符,而使用空格
            useTabs: false,
            // 行尾需要有分號(hào)
            semi: true,
            // 使用單引號(hào)
            singleQuote: true,
            // 對(duì)象的 key 僅在必要時(shí)用引號(hào)
            quoteProps: 'as-needed',
            // jsx 不使用單引號(hào),而使用雙引號(hào)
            jsxSingleQuote: false,
            // 末尾不需要逗號(hào)
            trailingComma: 'none',
            // 大括號(hào)內(nèi)的首尾需要空格
            bracketSpacing: true,
            // jsx 標(biāo)簽的反尖括號(hào)需要換行
            jsxBracketSameLine: false,
            // 箭頭函數(shù),只有一個(gè)參數(shù)的時(shí)候,也需要括號(hào)
            arrowParens: 'avoid',
            // 每個(gè)文件格式化的范圍是文件的全部?jī)?nèi)容
            rangeStart: 0,
            rangeEnd: Infinity,
            // 不需要寫(xiě)文件開(kāi)頭的 @prettier
            requirePragma: false,
            // 不需要自動(dòng)在文件開(kāi)頭插入 @prettier
            insertPragma: false,
            // 使用默認(rèn)的折行標(biāo)準(zhǔn)
            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()],
        };

        總結(jié)

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

        看完兩件事

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

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

        2.關(guān)注公眾號(hào)「前端技術(shù)江湖」,持續(xù)為你推送精選好文
        點(diǎn)個(gè)『在看』支持下 


        瀏覽 55
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            一级二级三级高清视频 | 免费 成人视频 | bl趴跪揉指扩弄嗯啊bl | 美女小骚逼 | 99久久久无码国产精品免费麻豆 | 超碰电影 | 奇米四区 | 国产在线xxxx | 艹逼视频在线观看 | 国产色情aⅴ一级毛片 |