使用webpack5從0到1搭建一個react項目

前言

在這以前,每開始一個新項目我都是使用現有的腳手架,這很是便於快速地啓動一個新項目,並且通用的腳手架一般考慮地更加全面,也有利於項目的穩定開發;不過對於一個小項目,根據需求本身搭建可能會更好,一方面小項目不須要腳手架那麼豐富的功能,另外一方面能夠提升對項目的掌控度以方便後期的擴展。javascript

這篇文章是在實踐中總結的,具備實操性,讀者可跟着一步步進行搭建,中間我會穿插一些原理,固然由於筆者的能力有限,不會特別深刻。css

預備知識html

  • 熟悉Javascript && HTML && CSS
  • 熟悉ES6+
  • 有能力搭建Nodejs環境
  • 會用命令行

目標java

  • 學習使用webpack5和爲何使用它
  • 用webpack5搭建開發環境
  • 用webpack5搭建生產環境

什麼是webpack

這有點老生常談了,不過爲了新同窗可以看下去,在這裏簡單介紹一下。一個現代化的web應用,已經不是單純地優html、css、javascript組成的,它還須要對應用進行打包、壓縮和編譯成瀏覽器可以理解的代碼,因而webpack就開始流行起來了。node

webpack是一個模塊打包器,它能夠打包任何東西。你能夠在開發時使用最新的Javascript特性或Typescirpt,webpack會將它編譯成瀏覽器支持的代碼並壓縮它;你還能夠在Javascript中導入須要用到的靜態資源。react

在開發過程當中,webpack提供了開發服務器並支持HMR,什麼是HMR和怎麼配置後面會詳細介紹,如今咱們只要知道當咱們保存代碼的時候webpack會幫咱們自動從新編譯和刷新瀏覽器。webpack

webpack的能作的遠不止這些,這篇文章主要是幫助你熟悉基本概念和如何去配置本身的腳手架。es6

開始搭建

這篇文章算是一個較爲完整的實戰教程,目標是搭建一個可用的腳手架,在此基礎上能夠擴展出更多的功能。web

架構須要支持的特性typescript

  • Webpack5

  • 命令行友好提示

  • es6+

  • React

  • Typescript

  • PostCSS + cssnext

  • HMR

安裝webpack

新建一個項目,進入項目根目錄,建立默認的package.json

yarn init -y
複製代碼

安裝webpackwebpack-cli

  • webpack - 模塊打包庫
  • webpack-cli - 命令行工具
yarn add webpack webpack-cli -D
複製代碼

基礎配置

在根目錄下新建一個webpack.config.js

Entry

入口文件,webpack會首先從這裏開始編譯

// webpack.config.js
const path = require('path');

module.exports = {
  entry: {
    app: './src/index.js'
  },
}
複製代碼

Output

定義了打包後輸出的位置,以及對應的文件名。[name]是一個佔位符,這裏是根據咱們在entry中定義的key值,即等價於app

module.exports = {
  /* ... */

  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].bundle.js',
  },
}
複製代碼

確保src下有index.js,而後如今可使用咱們的最小化配置進行打包。在package.json中加入如下代碼

"scripts": {
  "build": "webpack"
}
複製代碼

運行該命令

yarn run build
複製代碼

能夠在命令行中看到打包的結果,而且在根目錄下生成了一個dist目錄,說明打包成功。

Plugins

插件使webpack具有可擴展性,可讓咱們支持更多的功能。

模板文件

當咱們構建一個web app的時候,咱們須要一個HTML頁,而後再HTML中引入Javascript,當咱們配置了打包輸出的bundle文件是隨機字符串時,每次手動更新就特別麻煩,因此最好的方法是能夠自動將bundle打包進HTML中。

  • Html-webpack-plugin - 從模板生成一個HTML文件

安裝

yarn add html-webpack-plugin -D
複製代碼

在根目錄下新建一個文件public/index.html,內容以下

<!DOCTYPE html>
<html lang="en">
  <head>
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>

  <body>
    <div id="root"></div>
  </body>
</html>
複製代碼

其中title是讀取html-webpack-plugin插件的配置,配置以下

// webpack.config.js

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  /* ... */

  plugins: [
    new HtmlWebpackPlugin({
      title: '鐵木真大屏展現',
      template: path.resolve(__dirname, './public/index.html'),
      filename: 'index.html',
    }),
  ],
}
複製代碼

如今咱們再次運行yarn run build,能夠看到dist下多了一個index.html,其中自動插入了標題和script,效果以下

image-20201215104729535

打包前清除dist

  • clean-webpack-plugin - 打包前移除/清理 打包目錄

安裝

yarn add clean-webpack-plugin -D
複製代碼

配置

const path = require('path')

const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  /* ... */

  plugins: [
    /* ... */
    new CleanWebpackPlugin(),
  ],
}
複製代碼

命令行友好提示

安裝

yarn add friendly-errors-webpack-plugin -D
複製代碼

配置

// webpack.config.js
const friendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

module.exports = {
  plugins: [
    new friendlyErrorsWebpackPlugin(),
  ]
}
複製代碼

Loaders

webpack使用loaders去解析模塊,webpack想要去如何理解Javascript、靜態資源(圖片、字體、css)、轉移Typescript和Babel,都須要配置相應的loader規則。

在項目中只有一個HTML和一些Javascript是沒什麼用的,咱們還須要webpack可以作一些事:

  • 將最新的Javascript特性編譯成瀏覽器理解的
  • 模塊化CSS,將編譯SCSS、cssnext編譯成CSS
  • 導入圖片、字體等靜態資源
  • 使用本身喜好的框架,如React

Babel

Babel 是一個 JavaScript 編譯器,能將 ES6 代碼轉爲 ES5 代碼,讓你使用最新的語言特性而不用擔憂兼容性問題,而且能夠經過插件機制根據需求靈活的擴展,咱們須要先安裝如下庫

yarn add babel-loader @babel/core -D
複製代碼
  • babel-loader - 使用Babel和webpack轉譯文件
  • @babel/core - 轉譯ES2015+的代碼

配置以下

// webpack.config.js
module.exports = {
  /* ... */

  module: {
    rules: [
      // JavaScript
      {
        test: /\.m?js$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
          },
        },
      },
    ],
  },
}
複製代碼

在 Babel 執行編譯的過程當中,會從項目根目錄下的配置文件讀取配置。在根目錄下建立Babel的配置文件babel.config.json

{
  "presets": ["@babel/preset-env"]
}
複製代碼

若是未安裝@babel/preset-env須要先安裝

yarn add @babel/preset-env -D
複製代碼

圖片和字體

解析圖片的loader配置

module.exports = {
  /* ... */
  module: {
    rules: [
      // Images
      {
        test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
        type: 'asset/resource',
      },
    ],
  },
}
複製代碼

解析字體文件的loader配置

module.exports = {
  /* ... */
  module: {
    rules: [
      // Fonts and SVGs
      {
        test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
        type: 'asset/inline',
      },
    ],
  },
}
複製代碼

樣式

如今咱們但願可以在Javascript中導入CSS,以及將CSS注入DOM,另外還想使用CSS的高級特性,如cssnext,須要依賴一下庫

  • css-loader - 解析CSS導入

  • style-loader - 將CSS注入DOM

  • postcss-loader - 用PostCSS處理CSS

    • postcss-preset-env - PostCSS的默認配置
  • postcss - PostCSS 是一個容許使用 JS 插件轉換樣式的工具。 這些插件能夠檢查(lint)你的 CSS,支持 CSS Variables 和 Mixins, 編譯還沒有被瀏覽器普遍支持的先進的 CSS 語法,內聯圖片,以及其它不少優秀的功能。

  • postcss-next - PostCSS的插件,可使用CSS最新的語法

安裝

yarn add css-loader style-loader postcss-loader postcss-preset-env postcss postcss-cssnext -D
複製代碼

新建PostCSS配置文件postcss.config.js,配置以下

module.exports = {
  plugins: {
    'postcss-preset-env': {
      browsers: 'last 2 versions',
    },
  },
}
複製代碼

配置loader

// webpack.config.js

module.exports = {
  /* ... */
  module: {
    rules: [
      // CSS, PostCSS, and Sass
      {
        test: /\.(scss|css)$/,
        use: ['style-loader', {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          }, 'postcss-loader'],
      },
    ],
  },
}
複製代碼

開發環境

讓咱們從設置配置爲開發模式開始,表示當前的配置的配置爲開發環境的配置

// webpack.config.js

module.exports = {
 mode: 'development',
 // ...
}
複製代碼

使用source maps

爲了在報錯的時候更好的追蹤代碼和給出錯誤代碼出現的地方的提示,咱們可使用source map,配置以下

// webpack.config.js

module.exports = {
 devtool: 'inline-source-map'
 // ...
}
複製代碼

HMR

當咱們改動代碼時,但願能自動從新編譯代碼,webpack提供了三種不一樣的方式:

  1. 監聽模式
  2. webpack-dev-server
  3. webpack-dev-middleware

大多數狀況,使用的是webpack-dev-server,本文也是使用這個,不過我會順帶介紹一下其它兩種方式,你們各取所需。

  • 使用監聽模式:
// package.json
{
  "watch": "webpack --watch"
}
複製代碼

執行如下命令

yarn run watch
複製代碼

如今當咱們保存代碼的時候會自動編譯代碼,刷新瀏覽器後便可看到效果;可是咱們想要自動刷新瀏覽器怎麼辦,這時候就輪到webpack-dev-server商場了。

  • webpack-dev-server

它爲咱們提供了一個服務器和live relaoding的能力,咱們須要首先安裝它

yarn add webpack-dev-server -D
複製代碼

而後配置以下

// webpack.config.js
module.exports = {
  // ...
  devServer: {
    historyApiFallback: true,
    contentBase: path.join(__dirname, './dist'),
    open: false,
    hot: true,
    quiet: true,
    port: 8082,
  },
}
複製代碼
// package.json
{
  "scripts": {
    "start": "webpack serve"
  }
}
複製代碼

咱們在8082端口監聽了一個服務,監聽的目錄是dist,而且支持HMR,如今打開http://localhost:8082,能夠看到咱們的頁面,而後改動代碼,瀏覽器會自動刷新更新效果,是否是很酷!

上面提到了HMR,它的全稱是Hot Module Replacement,翻譯過來就是熱模塊替換,我認爲它是webpack提供的最有用的一個特性,它容許咱們只更新改動過的模塊,而不需有所有更新,咱們在上面已經開啓了該功能,即hot: true

  • webpack-dev-middleware

這是一個webpack的中間件,可讓webpack把文件交給一個服務器處理,好比接下來要使用的express,這給了咱們更多的控制權,接下來簡單演示一下。

安裝expresswebpack-dev-middleware

yarn add express webpack-dev-middleware -D
複製代碼

更改配置

module.exports = {
  //...
  output: {
    //...
    publicPath: '/'
  }
}
複製代碼

publicPath能夠定義了express監聽服務的路徑,接下來就建立咱們的express`服務器

新建一個server.js

const express = require('express');
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');

const app = express();
const config = require('./webpack.config.js');
const compiler = webpack(config);

// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(
  webpackDevMiddleware(compiler, {
    publicPath: config.output.publicPath,
  })
);

// Serve the files on port 3000.
app.listen(3000, function () {
  console.log('Example app listening on port 3000!\n');
});
複製代碼

監聽端口爲3000,執行如下命令啓動服務

node server.js
複製代碼

方便起見,能夠將該命令加入package.json

{
  //...
  "scripts": {
    "server": "node server.js"
  }
}
複製代碼

使用Typescript

安裝依賴

yarn add typescript ts-loader -D
複製代碼

在根目錄下建立typescript的配置文件tsconfig.json,具體配置以下

{
  "compilerOptions": {
    "outDir": "./dist/",
    // "rootDir": "./src",
    "sourceMap": true, // 開啓sourcemap
    "module": "commonjs",
    "target": "es5",
    "jsx": "react",
    "esModuleInterop": true,
    "allowJs": true,
    "strict": true
  }
}

複製代碼
// webpack.config.js
module.exports = {
  //...
  module: {
    rules: [
       {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ]
  }
}
複製代碼

使用React

在上面配置typescript中,已經開啓了支持react,如今只需安裝react的依賴便可

yarn add react react-dom @types/react @types/react-dom
複製代碼

而後將入口文件改爲.tsx後綴,內容以下

import React from 'react';
import ReactDOM from 'react-dom';

import './index.css';

const App = () => {
  return <div>hello world2</div>;
};

ReactDOM.render(<App />, document.getElementById('root'));
複製代碼

代碼規範

Prettier

Prettier是一個誕生於2016年就迅速流行起來的專一於代碼格式化的工具。出道即巔峯啊-.- Prettier只關注格式化,並不具備lint檢查語法等能力。它經過解析代碼並匹配本身的一套規則,來強制執行一致的代碼展現格式。 它在美化代碼方面有很大的優點,配合ESLint能夠對ESLint格式化基礎上作一個很好的補充。

使用

以VSCode爲例,安裝Prettier插件便可使用,若是想自定義配置,能夠cmd+,快捷鍵進入vscode配置,搜索Prettier找到對應的配置項進行配置。

Eslint

ESLint 是一個在 JavaScript 代碼中經過規則模式匹配做代碼識別和報告的插件化的檢測工具,它的目的是保證代碼規範的一致性和及時發現代碼問題、提早避免錯誤發生。 ESLint 的關注點是代碼質量,檢查代碼風格而且會提示不符合風格規範的代碼。除此以外 ESLint 也具備一部分代碼格式化的功能。

安裝依賴,方便起見,直接使用已有的Eslint配置,這裏使用的是fabric

yarn add @umijs/fabric -D
複製代碼

根目錄下新建.eslintrc.js,配置以下

module.exports = {
  extends: [require.resolve('@umijs/fabric/dist/eslint')],
  globals: {},
  plugins: ['react-hooks'],
  rules: {
    'no-restricted-syntax': 0,
    'no-param-reassign': 0,
    'no-unused-expressions': 0,
  },
};
複製代碼

重啓編輯器,便可應用Eslint的配置。

總結

到目前爲止,咱們搭建了一個簡易的react腳手架,而且它支持typescriptcssnext、HMR等特性,對於一個小項目來講已經足夠用了,你們能夠在此基礎上進行擴展;後面有時間的話會和你們一塊兒討論一下webpack稍底層的原理,是從源碼的角度去看。

附錄

how-to-use-webpack

webpack官網

相關文章
相關標籤/搜索