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開發(fā)環(huán)境(詳細(xì)篇)

        共 14850字,需瀏覽 30分鐘

         ·

        2021-02-21 01:24


        作者 @劉江?,原文地址 https://juejin.cn/post/6929496472232656909

        本文作者投稿文章,如需轉(zhuǎn)載請(qǐng)聯(lián)系作者授權(quán)。

        前言

        為什么要自己造輪子?起初是因?yàn)樽约翰⒉粷M意市面上的腳手架。另外,造輪子對(duì)于自己也有一些技術(shù)上的幫助,學(xué)別人二次封裝的東西,不如直接使用底層的庫(kù),這樣也有助于自己系統(tǒng)的學(xué)習(xí)一遍知識(shí),廢話不多說(shuō),直接進(jìn)入正文,如何搭建自己的開發(fā)環(huán)境。

        初始化

        創(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



        ????
        ????????"utf-8"?/>
        ????????tristana
        ????
        ????
        ????????
        ????????"root">

        ????

        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,如果一切正常,你應(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



        ????
        ????????"utf-8"?/>
        ????????tristana
        ????
        ????
        ????????"root">

        ????

        開發(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?(
        ????????????

        ????????????????

        ?Hello,?World!?


        ????????????

        ????????);
        ????}
        }

        export?default?App;

        src/index.js

        import?React?from?"react";
        import?ReactDOM?from?"react-dom";
        import?App?from?"./App.jsx";
        ReactDOM.render(,?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(
        ????history={createBrowserHistory()}>
        ????????"/"?component={App}?/>
        ????????"/about"?component={About}?/>
        ????,
        ????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(
        ????
        ????????history={createBrowserHistory()}>
        ????????"/"?component={App}?/>
        ????????"/about"?component={About}?/>
        ????????
        ????,
        ????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?(
        ????????????

        ????????????????
        {this.props.store.count}

        ????????????????add
        ????????????????reduce
        ????????????

        ????????);
        ????}
        }

        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?(
        ????????????

        ????????????????
        ????????????

        ????????);
        ????}
        }

        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?(
        ????????????

        ????????????????
        ????????????????
        {this.props.store.count}

        ????????????????add
        ????????????????reduce
        ????????????

        ????????);
        ????}
        }

        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,
        ????//?不需要寫文件開頭的?@prettier
        ????requirePragma:?false,
        ????//?不需要自動(dòng)在文件開頭插入?@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?開發(fā)環(huán)境可以看這個(gè)tristana,求點(diǎn)贊,求關(guān)注!

        ??愛(ài)心三連擊

        1.看到這里了就點(diǎn)個(gè)在看支持下吧,你的點(diǎn)贊,在看是我創(chuàng)作的動(dòng)力。

        2.關(guān)注公眾號(hào)程序員成長(zhǎng)指北,回復(fù)「1」加入高級(jí)前端交流群!「在這里有好多 前端?開發(fā)者,會(huì)討論?前端 Node 知識(shí),互相學(xué)習(xí)」!

        3.也可添加微信【ikoala520】,一起成長(zhǎng)。

        “在看轉(zhuǎn)發(fā)”是最大的支持


        瀏覽 49
        點(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>
            亚洲n∨ www.操.com | 思思热在线观看 | 丁香五月深深爱 | 老女人裸体视频 | 人人妻人人澡 | 丰满女人的毛片久久久久久 | 日本操B| 日韩在线三级片 | 双龙h啊~嗯啊h巨大漫画 | 国产强伦轩免费视频在线 |