快來(lái)跟我一起學(xué) React(Day3)

簡(jiǎn)介

上一節(jié)我們介紹了 React 官方提供的腳手架(create-react-app)卜录,然后用官方腳手架創(chuàng)建了一個(gè) react-demo1 項(xiàng)目,用腳手架創(chuàng)建出來(lái)的項(xiàng)目算是 React 官方認(rèn)為的最佳項(xiàng)目實(shí)踐了券躁,但是從上一節(jié)使用中我們可以看出,官方腳手架可還是有一些弊端掉盅,它只提供一些可改的 webpack 配置也拜,如果你想自己添加一個(gè) loaderplugin 什么的趾痘,你可能就需自定義 webpack 配置了慢哈,就不能在依賴腳手架了,既然是重新學(xué)習(xí) React永票,我們就來(lái)挑戰(zhàn)一下自己卵贱,從 0 開(kāi)始搭建一個(gè)企業(yè)級(jí)的 React 項(xiàng)目滥沫,大家跟緊節(jié)奏吧。

知識(shí)點(diǎn)

  • Webpack (打包編譯)
  • TypeScript(語(yǔ)法規(guī)范)
  • React(js 框架)
  • html-webpack-plugin(webpack 插件)
  • Sass(css 預(yù)處理框架)
  • PostCss(css 預(yù)處理框架)
  • mini-css-extract-plugin(提取 css 模塊插件)
  • Babel( es 語(yǔ)法轉(zhuǎn)化)
  • Jsx & Tsx(jsx 語(yǔ)法)
  • ESLint(代碼質(zhì)量校驗(yàn))
  • Optimization(項(xiàng)目?jī)?yōu)化)

ok艰赞!要搭建一個(gè)企業(yè)級(jí)的項(xiàng)目需要準(zhǔn)備的東西還是有點(diǎn)多的佣谐,我們分一下類:

  • Js 框架(Vue、TypeScript方妖、Tsx狭魂、Jsx)
  • Css 樣式(Sass)
  • 工程化工具(Eslint、Babel党觅、webpack雌澄、webpack-chain)

我們開(kāi)始吧。

項(xiàng)目初始化

我們創(chuàng)建一個(gè) cus-react-demo 目錄杯瞻,然后在 cus-react-demo 目錄下執(zhí)行 npx init -y 命令:

mkdir cus-react-demo && cd cus-react-demo && npm init -y
1

如上圖所示镐牺,初始化完畢后會(huì)看到一個(gè) package.json 文件。

webpack

接下來(lái)我們需要安裝 webpack 相關(guān)的依賴:

安裝 webpack

webpack 核心庫(kù)魁莉。

在工程目錄 cus-react-demo 執(zhí)行以下命令安裝 webpack:

npm install -D webpack --registry https://registry.npm.taobao.org

目前 webpack 的版本是 5.26.3睬涧。

安裝 webpack-cli

webpack 指令庫(kù)。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D webpack-cli --registry https://registry.npm.taobao.org

安裝 webpack-dev-server

webpack 開(kāi)發(fā)者服務(wù)框架旗唁。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D webpack-dev-server --registry https://registry.npm.taobao.org

安裝 webpack-chain

webpack 配置工具畦浓。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D webpack-chain --registry https://registry.npm.taobao.org

創(chuàng)建 webpack 配置

在工程目錄 cus-react-demo 下創(chuàng)建一個(gè) webpack.config.js 文件:

touch webpack.config.js

然后對(duì) webpack.config.js 進(jìn)行配置,用 webpack-chain 導(dǎo)入一個(gè) webpack 配置:

const config = new (require('webpack-chain'))();

module.exports = config.toConfig();

安裝 cross-env

定義 node 中的 process.env 中的變量检疫。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D cross-env --registry https://registry.npm.taobao.org

為了開(kāi)發(fā)方便讶请,我們?cè)?package.json 中聲明兩個(gè)腳本 builddev

{
  "name": "cus-react-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "rimraf dist && cross-env NODE_ENV=production webpack --mode=production",
    "start": "cross-env NODE_ENV=development webpack serve --mode=development --progress"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "cross-env": "^7.0.3",
    "webpack": "^5.26.3",
    "webpack-chain": "^6.5.1",
    "webpack-cli": "^4.5.0",
    "webpack-dev-server": "^3.11.2"
  }
}

我們可以試著運(yùn)行一下 buildstart 腳本命令:

npm start
1-2.png

現(xiàn)在運(yùn)行肯定是報(bào)錯(cuò)的,因?yàn)槲覀冞€沒(méi)有對(duì)項(xiàng)目進(jìn)行任何配置屎媳。

入口與出口

我們首先在工程目錄 cus-react-demo 下創(chuàng)建一個(gè) src 目錄夺溢,然后在 src 目錄下創(chuàng)建一個(gè) main.tsx 文件:

mkdir src && cd src && touch main.tsx && cd ..

然后我們找到 webpack.config.js 文件,對(duì) webpack 的入口和出口進(jìn)行配置:

const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判斷是否是開(kāi)發(fā)環(huán)境
config
    .context(path.resolve(__dirname, '.')) // webpack 上下文目錄為項(xiàng)目根目錄
    .entry('app') // 入口文件名稱為 app
        .add('./src/main.tsx') // 入口文件為 ./src/main.tsx
        .end()
    .output
        .path(path.join(__dirname, './dist')) // webpack 輸出的目錄為根目錄的 dist 目錄
        .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出來(lái)的 bundle 名稱為 "[name].[contenthash:8].js"
        .publicPath('/') // publicpath 配置為 "/"
        .end();
module.exports = config.toConfig();

可以看到烛谊,我們配置了一個(gè) app 入口 ./src/main.ts风响,然后給所有的輸出文件名稱改成了 [name].[hash:8].js

我們?cè)俅螆?zhí)行 build 命令:

npm run build
1-3.png

可以看到丹禀,這次沒(méi)有報(bào)錯(cuò)了状勤。

但是當(dāng)我們給 src/main.tsx 添加點(diǎn)內(nèi)容試試:

let a: string = 'hello';

我們?cè)俅芜\(yùn)行 npm run build 命令:

1-4.png

可以看到,又報(bào)錯(cuò)了湃崩,這次是因?yàn)?webpack 沒(méi)法去解析 main.tsx 中的 ts 語(yǔ)法荧降,所以接下來(lái)我們就需要配置一下 webpackloader 了接箫,讓我們的項(xiàng)目能夠支持 jsx攒读、tstsx 語(yǔ)法辛友。

Babel & TypeScript

因?yàn)槲覀冺?xiàng)目是需要支持 ts 語(yǔ)法的薄扁,所以我們需要安裝一下 TypeScript 相關(guān)依賴:

babel-preset-react-app

很幸運(yùn)哈剪返,React 官方已經(jīng)提供了一套 babel 插件集合,它會(huì)自動(dòng)的幫我們添加 babel 相關(guān)的配置邓梅,讓我們能夠輕松的使用 jsx脱盲、tstsx 語(yǔ)法日缨,而且不需要考慮 es 語(yǔ)法的兼容性問(wèn)題钱反,會(huì)根據(jù)我們的瀏覽器配置自動(dòng)做語(yǔ)法兼容等操作。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D babel-preset-react-app --registry https://registry.npm.taobao.org

babel-loader

webpack 加載器匣距。

在工程目錄 cus-react-demo 下執(zhí)行以下命令安裝:

npm install -D babel-loader --registry https://registry.npm.taobao.org

ok面哥!安裝完 Babel 的一些依賴后,我們開(kāi)始配置 webpack毅待。

找到 webpack.config.js 文件尚卫,然后添加 babel-loader 配置:

const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判斷是否是開(kāi)發(fā)環(huán)境
config
    .context(path.resolve(__dirname, '.')) // webpack 上下文目錄為項(xiàng)目根目錄
    .entry('app') // 入口文件名稱為 app
        .add('./src/main.tsx') // 入口文件為 ./src/main.tsx
        .end()
    .output
        .path(path.join(__dirname, './dist')) // webpack 輸出的目錄為根目錄的 dist 目錄
        .filename('[name].[contenthash:8].js') // 打包出來(lái)的 bundle 名稱為 "[name].[contenthash:8].js"
        .publicPath('/') // publicpath 配置為 "/"
        .end()
    .resolve
        .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后綴自動(dòng)解析
        .end()
    .module
        .rule('ts') // 配置 typescript
            .test(/\.(js|mjs|jsx|ts|tsx)$/)
            .exclude
                .add(filepath => {
                    // Don't transpile node_modules
                    return /node_modules/.test(filepath)
                })
                .end()
            .use('babel-loader')
                .loader('babel-loader')
                .end()
            .end()
module.exports = config.toConfig();

然后我們需要在工程目錄 cus-react-demo 下創(chuàng)建一個(gè)文件 babel.config.js

touch babel.config.js

然后寫入以下代碼到 babel.config.js 文件:

module.exports = {
    presets: [
        [
            "babel-preset-react-app", // 添加 react-app 插件集合
        ],
    ]
}

TypeScript 配置

因?yàn)槲覀冃枰M(jìn)行 ts 語(yǔ)法的我們還需要在工程目錄 cus-react-demo 下創(chuàng)建一個(gè) ts 配置文件 tsconfig.json

touch tsconfig.json

然后寫入以下代碼到 tsconfig.json 文件:

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "suppressImplicitAnyIndexErrors": true,
    "resolveJsonModule": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": ["webpack-env"],
    "paths": {
      "@/*": ["src/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable"]
  },
  "include": ["src/**/*.ts", "src/**/*.tsx",],
  "exclude": ["node_modules"]
}

ok!我們?cè)俅芜\(yùn)行 npm run build 命令:

1-5.png

可以看到尸红,這一次 webpack 正常完成了編譯打包吱涉。

React 配置

我們首先安裝一下 React 所需要的依賴:

安裝 react & react-dom

React 核心 API。

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install react react-dom @types/react @types/react-dom --registry https://registry.npm.taobao.org

然后我們修改一下 src/main.tsx 文件來(lái)測(cè)試一下:

import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
    <div>hello react</div>,
    document.getElementById('root')
);

很簡(jiǎn)單外里,就是利用 tsx 語(yǔ)法在頁(yè)面中輸出了一句 “hello react” 字符串怎爵。

如果需要開(kāi)啟 webpack-dev-server 的話,我們還需要配置一下 devServer级乐。

我們找到 webpack.config.js 配置文件疙咸,然后添加 devServer 配置:

const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判斷是否是開(kāi)發(fā)環(huán)境
config
    .context(path.resolve(__dirname, '.')) // webpack 上下文目錄為項(xiàng)目根目錄
    .entry('app') // 入口文件名稱為 app
        .add('./src/main.tsx') // 入口文件為 ./src/main.tsx
        .end()
    .output
        .path(path.join(__dirname, './dist')) // webpack 輸出的目錄為根目錄的 dist 目錄
        .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出來(lái)的 bundle 名稱為 "[name].[contenthash:8].js"
        .publicPath('/') // publicpath 配置為 "/"
        .end()
    .resolve
        .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后綴自動(dòng)解析
        .end()
    .module
        .rule('ts') // 配置 typescript
            .test(/\.(js|mjs|jsx|ts|tsx)$/)
            .exclude
                .add(filepath => {
                    // Don't transpile node_modules
                    return /node_modules/.test(filepath)
                })
                .end()
            .use('babel-loader')
                .loader('babel-loader')
                .end()
            .end()
    .end()
    .devServer
        .host('0.0.0.0') // 服務(wù)器外部可訪問(wèn)
        .disableHostCheck(true) // 關(guān)閉白名單校驗(yàn)
        .contentBase(path.resolve(__dirname, './public')) // 設(shè)置一個(gè) express 靜態(tài)目錄
        .historyApiFallback({
            disableDotRule: true, // 禁止在鏈接中使用 "." 符號(hào)
            rewrites: [
                { from: /^\/$/, to: '/index.html' }, // 將所有的 404 響應(yīng)重定向到 index.html 頁(yè)面
            ],
        })
        .port(8080) // 當(dāng)前端口號(hào)
        .hot(true) // 打開(kāi)頁(yè)面熱載功能
        .sockPort('location'); // 設(shè)置成平臺(tái)自己的端口
module.exports = config.toConfig();

ok!然后我們?cè)诠こ棠夸?cus-react-demo 下執(zhí)行 npm start 開(kāi)啟 webpack-dev-server

npm start

執(zhí)行完畢后风科,我們可以直接用瀏覽器訪問(wèn)一下打包過(guò)后的目錄(http://127.0.0.1:8080/webpack-dev-server):

1-6.png

可以看到撒轮,webpack-dev-server 列出了 webpack 打包出來(lái)的所有 js 資源文件。

接下來(lái)我們?cè)诠こ棠夸?cus-react-demo 底下創(chuàng)建一個(gè) public 目錄贼穆,然后在 public 目錄下創(chuàng)建一個(gè) index.html 文件作為我們 app 的入口頁(yè)面:

mkdir public && touch public/index.html

然后寫入以下代碼到 public/index.html 文件:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <noscript>your browser should support javascript!</noscript>
    <!-- 掛載點(diǎn) -->
    <div id="root"></div>
    <!-- 引入入口文件 -->
    <!-- 注意题山!這里的 64a558f4 每個(gè)人是不一樣的 -->
    <script src="/app.64a558f4.js"></script>
  </body>
</html>

注意!這里的 64a558f4 每個(gè)人是不一樣的)創(chuàng)建完畢后故痊,我們重啟服務(wù):

npm start

然后我們可以直接用瀏覽器訪問(wèn) http://127.0.0.1:8080/ 項(xiàng)目入口了:

1-7.png

可以看到顶瞳,頁(yè)面渲染了我們?cè)?src/index.js 入口文件中定義的 “hello react” 字符串。

html-webpack-plugin

雖然瀏覽器中正常顯示了我們的結(jié)果愕秫,但是我們現(xiàn)在還是手動(dòng)去引入 app.xxx.js 文件的慨菱,而 xxx 是經(jīng)常變化的,所以我們不可能每次都去改 public/index.html 文件戴甩,能不能自動(dòng)去引入 js 資源文件到入口 index.html 呢符喝?

安裝 html-webpack-plugin

在工程目錄 cus-react-demo 執(zhí)行以下命令:

npm install -D html-webpack-plugin --registry https://registry.npm.taobao.org

然后修改一下 webpack.config.js 配置文件,引入 html-webpack-plugin 插件:

const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判斷是否是開(kāi)發(fā)環(huán)境
config
        .target('web')
    .context(path.resolve(__dirname, '.')) // webpack 上下文目錄為項(xiàng)目根目錄
    .entry('app') // 入口文件名稱為 app
        .add('./src/main.tsx') // 入口文件為 ./src/main.tsx
        .end()
    .output
        .path(path.join(__dirname, './dist')) // webpack 輸出的目錄為根目錄的 dist 目錄
        .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出來(lái)的 bundle 名稱為 "[name].[contenthash:8].js"
        .publicPath('/') // publicpath 配置為 "/"
        .end()
    .resolve
        .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后綴自動(dòng)解析
        .end()
    .module
        .rule('ts') // 配置 typescript
            .test(/\.(js|mjs|jsx|ts|tsx)$/)
            .exclude
                .add(filepath => {
                    // Don't transpile node_modules
                    return /node_modules/.test(filepath)
                })
                .end()
            .use('babel-loader')
                .loader('babel-loader')
                .end()
            .end()
    .end()
    .plugin('html') // 添加 html-webpack-plugin 插件
        .use(require('html-webpack-plugin'), [
            {
                template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                chunks: ['app'], // 指定需要加載的 chunk
                inject: 'body', // 指定 script 腳本注入的位置為 body
            },
        ])
        .end()
    .devServer
        .host('0.0.0.0') // 服務(wù)器外部可訪問(wèn)
        .disableHostCheck(true) // 關(guān)閉白名單校驗(yàn)
        .contentBase(path.resolve(__dirname, './public')) // 設(shè)置一個(gè) express 靜態(tài)目錄
        .historyApiFallback({
            disableDotRule: true, // 禁止在鏈接中使用 "." 符號(hào)
            rewrites: [
                { from: /^\/$/, to: '/index.html' }, // 將所有的 404 響應(yīng)重定向到 index.html 頁(yè)面
            ],
        })
        .port(8080) // 當(dāng)前端口號(hào)
        .hot(true) // 打開(kāi)頁(yè)面熱載功能
        .sockPort('location'); // 設(shè)置成平臺(tái)自己的端口
module.exports = config.toConfig();

ok甜孤!配置完畢后协饲,我們就可以去掉 public/index.html 中的入口 js 文件了畏腕,讓其自動(dòng)引入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <title>Title</title>
</head>
<body>
<noscript>your browser should support javascript!</noscript>
<!-- 掛載點(diǎn) -->
<div id="root"></div>
<!-- html-webpack-plugin 將自動(dòng)引入入口文件 -->
</body>
</html>

我們?cè)俅螆?zhí)行 npm start 命令啟動(dòng)項(xiàng)目:

npm start

效果跟之前一致,我就不演示了茉稠。

css 樣式(Sass)

安裝 Sass

Sass & Scss 語(yǔ)法核心 API描馅。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D sass --registry https://registry.npm.taobao.org

安裝 sass-loader

Sass & Scss 文件加載器。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D sass-loader --registry https://registry.npm.taobao.org

安裝 postcss-loader

css 樣式處理工具而线,自動(dòng)添加瀏覽器適配前綴铭污、壓縮 css 樣式等等。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D postcss-loader --registry https://registry.npm.taobao.org

然后我們?cè)诠こ棠夸?sy_webpack-wedding 下創(chuàng)建一個(gè) postcss.config.js 作為 postcss 的配置文件:

touch postcss.config.js

寫入以下代碼到 postcss.config.js 文件:

module.exports = {
  plugins: [
    require('autoprefixer')(), // 添加 autoprefixer 插件做自動(dòng)添加樣式前綴
    require('cssnano')({
      // 添加 cssnano 插件做 css 代碼壓縮
      preset: [
        'default',
        {
          mergeLonghand: false,
          cssDeclarationSorter: false,
        },
      ],
    }),
  ],
};

安裝 cssnano

壓縮 css 代碼膀篮。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D cssnano --registry https://registry.npm.taobao.org

安裝 autoprefixer

自動(dòng)添加瀏覽器樣式適配前綴况凉。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D autoprefixer@^9.8.5 --registry https://registry.npm.taobao.org

要讓 autoprefixer 插件起作用,我們還需要配置一個(gè)項(xiàng)目所支持的瀏覽器列表文件 .browserslistrc各拷,于是我們?cè)诠こ棠夸?sy_webpack-wedding 下創(chuàng)建一個(gè) .browserslistrc 文件:

touch .browserslistrc

然后寫入以下內(nèi)容到 .browserslistrc 文件:

> 0.25%, not dead

意思就是告訴 autoprefixer 插件刁绒,我們項(xiàng)目需要兼容的瀏覽器是 “大于市面上 0.25% 使用率的瀏覽器,請(qǐng)根據(jù)我配置的瀏覽器列表自動(dòng)判讀是否應(yīng)該添加 css 前綴做兼容”烤黍。

安裝 css-loader

css 模塊加載器知市。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D css-loader --registry https://registry.npm.taobao.org

安裝 mini-css-extract-plugin

抽離 css 樣式到獨(dú)立的 .css 文件。

在工程目錄 sy_webpack-wedding 執(zhí)行以下命令:

npm install -D mini-css-extract-plugin --registry https://registry.npm.taobao.org

ok速蕊!安裝完 Sass 相關(guān)的依賴后嫂丙,我們來(lái)修改一下 webpack.config.js 文件,讓 webpack 支持 Sass

const path = require('path');
const config = new (require('webpack-chain'))();
const isDev = process.env.NODE_ENV === 'development'; // 判斷是否是開(kāi)發(fā)環(huán)境
config
    .target('web')
    .context(path.resolve(__dirname, '.')) // webpack 上下文目錄為項(xiàng)目根目錄
    .entry('app') // 入口文件名稱為 app
        .add('./src/main.tsx') // 入口文件為 ./src/main.tsx
        .end()
    .output
        .path(path.join(__dirname, './dist')) // webpack 輸出的目錄為根目錄的 dist 目錄
        .filename(isDev ? '[name].[hash:8].js' : '[name].[contenthash:8].js') // 打包出來(lái)的 bundle 名稱為 "[name].[contenthash:8].js"
        .publicPath('/') // publicpath 配置為 "/"
        .end()
    .resolve
        .extensions.add('.js').add('.jsx').add('.ts').add('.tsx').end() // 添加后綴自動(dòng)解析
        .end()
    .module
        .rule('ts') // 配置 typescript
            .test(/\.(js|mjs|jsx|ts|tsx)$/)
            .exclude
                .add(filepath => {
                    // Don't transpile node_modules
                    return /node_modules/.test(filepath)
                })
                .end()
            .use('babel-loader')
                .loader('babel-loader')
                .end()
            .end()
        .rule('sass') // sass-loader 相關(guān)配置
            .test(/\.(sass|scss)$/) // Sass 和 Scss 文件
            .use('extract-loader') // 提取 css 樣式到單獨(dú) css 文件
                .loader(require('mini-css-extract-plugin').loader)
                .end()
            .use('css-loader') // 加載 css 模塊
                .loader('css-loader')
                .end()
            .use('postcss-loader') // 處理 css 樣式
                .loader('postcss-loader')
                .end()
            .use('sass-loader') // Sass 語(yǔ)法轉(zhuǎn) css 語(yǔ)法
                .loader('sass-loader')
                .end()
            .end()
        .end()
    .plugin('extract-css') // 提取 css 樣式到單獨(dú) css 文件
        .use(require('mini-css-extract-plugin'), [
            {
                filename: isDev ? 'css/[name].css': 'css/[name].[contenthash].css',
                chunkFilename: isDev ? 'css/[id].css': 'css/[name].[contenthash].css',
            },
        ])
        .end()
    .plugin('html') // 添加 html-webpack-plugin 插件
        .use(require('html-webpack-plugin'), [
            {
                template: path.resolve(__dirname, './public/index.html'), // 指定模版文件
                chunks: ['app'], // 指定需要加載的 chunk
                inject: 'body', // 指定 script 腳本注入的位置為 body
            },
        ])
        .end()
    .devServer
        .host('0.0.0.0') // 服務(wù)器外部可訪問(wèn)
        .disableHostCheck(true) // 關(guān)閉白名單校驗(yàn)
        .contentBase(path.resolve(__dirname, './public')) // 設(shè)置一個(gè) express 靜態(tài)目錄
        .historyApiFallback({
            disableDotRule: true, // 禁止在鏈接中使用 "." 符號(hào)
            rewrites: [
                { from: /^\/$/, to: '/index.html' }, // 將所有的 404 響應(yīng)重定向到 index.html 頁(yè)面
            ],
        })
        .port(8080) // 當(dāng)前端口號(hào)
        .hot(true) // 打開(kāi)頁(yè)面熱載功能
        .sockPort('location') // 設(shè)置成平臺(tái)自己的端口
        .open(true)
module.exports = config.toConfig();

測(cè)試

我們?cè)?src 目錄底下創(chuàng)建一個(gè) main.scss 樣式文件:

touch ./src/main.scss

然后寫入點(diǎn)樣式到 src/main.scss 文件:

.root{
  color: red;
  font-size: 30px;
}

接著我們修改一下 src/main.tsx 文件规哲,引入 main.scss 樣式:

import React from 'react';
import ReactDOM from 'react-dom';
import "./main.scss";
ReactDOM.render(
    <div className="root">hello react</div>,
    document.getElementById('root')
);

可以看到跟啤,我們引入了 main.scss 樣式文件,然后給 div 元素上添加了一個(gè) root 類名唉锌。

我們重新運(yùn)行項(xiàng)目看結(jié)果:

npm start
1-8.gif

可以看到隅肥,當(dāng)我們修改樣式跟內(nèi)容的時(shí)候,頁(yè)面實(shí)時(shí)刷新了袄简。

這一節(jié)有點(diǎn)長(zhǎng)腥放,先到這里了。

總結(jié)

我們從 0 開(kāi)始搭建了一個(gè)項(xiàng)目绿语,完成了入口與出口的配置秃症、ts 語(yǔ)法支持、react 基本庫(kù)的安裝吕粹、css 樣式配置等工作种柑,跟上的小伙伴要給你們點(diǎn)個(gè)贊哦,所以整個(gè)下來(lái)基本上是對(duì) webpack 的配置工作(對(duì) webpack 不熟的小伙伴匹耕,強(qiáng)烈推薦去看我前面的文章 《來(lái)和 webpack 談場(chǎng)戀愛(ài)吧》:https://www.lanqiao.cn/courses/2893)聚请,到這我們只完成了一半的配置工作,我們下節(jié)繼續(xù)泌神。

歡迎志同道合的小伙伴一起交流良漱,一起學(xué)習(xí),歡迎私信我~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末欢际,一起剝皮案震驚了整個(gè)濱河市母市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌损趋,老刑警劉巖患久,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異浑槽,居然都是意外死亡蒋失,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門桐玻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)篙挽,“玉大人,你說(shuō)我怎么就攤上這事镊靴∠晨ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵偏竟,是天一觀的道長(zhǎng)煮落。 經(jīng)常有香客問(wèn)我,道長(zhǎng)踊谋,這世上最難降的妖魔是什么蝉仇? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮殖蚕,結(jié)果婚禮上轿衔,老公的妹妹穿的比我還像新娘。我一直安慰自己睦疫,他們只是感情好呀枢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著笼痛,像睡著了一般裙秋。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缨伊,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天摘刑,我揣著相機(jī)與錄音,去河邊找鬼刻坊。 笑死枷恕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谭胚。 我是一名探鬼主播徐块,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼未玻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了胡控?” 一聲冷哼從身側(cè)響起扳剿,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎昼激,沒(méi)想到半個(gè)月后庇绽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡橙困,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年瞧掺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凡傅。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辟狈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夏跷,到底是詐尸還是另有隱情上陕,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布拓春,位于F島的核電站释簿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏硼莽。R本人自食惡果不足惜庶溶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望懂鸵。 院中可真熱鬧偏螺,春花似錦、人聲如沸匆光。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)终息。三九已至夺巩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間周崭,已是汗流浹背柳譬。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留续镇,地道東北人美澳。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親制跟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子舅桩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354