Webpack5 React的配置

2,223 阅读3分钟

一:初始化环境

初始化 package.json文件

yarn init -y

安装Webpack

webpack-cli 是webpack的命令行工具,可以在命令行中使用webpack

yarn add -D webpack webpack-cli

配置react支持

yarn add react react-dom

在根目录下创建webpack.config.js 文件

二:配置react环境

配置babel环境支持

  • babel-loader
  • @babel/core
  • @babel/preset-env
  • @babel/plugin-transform-runtime
  • @babel/preset-react

babel-loader 将jsx文件转译为JS文件

jsx文件写出来的Dom,实际上会通过bable 翻译成对象的形式

@babel/core 内部核心模块的转译实现

babel-loader 仅仅是识别出了jsx 文件,内部的核心模块的转译需要@babel/core 实现

@babel/preset-env 将基础的ES6语法向下转译,兼容不同的浏览器

@babel/preset-env 只会转译一些低级的ES6语法,高级的语法,async await ,Promise是无法转换的

@babel/plugin-transform-runtime 转译高级的ES6语法

@babel/plugin-transform-runtime 将高级的ES6语法向下转译,兼容不同的浏览器

@babel/preset-react

内置了一系列babel plugin去转化jsx代码成为我们想要的js代码

安装babel环境插件

yarn add -D @babel/core @babel/preset-env babel-loader @babel/plugin-transform-runtime @babel/preset-react

在根目录下的webpack.config.js 文件中进行配置

{
    test: /\.jsx?$/,
    use: "babel-loader",
},

1646359020(1).png

在根目录下新建.babelrc文件

{
    "presets": [
      "@babel/preset-env",
      "@babel/preset-react"
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "regenerator": true
        }
      ]
    ]
}

在根目录下新建src文件夹,src文件夹下新建index.jsx 文件

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

const App = () => {
  return (
    <div>Webacpk5</div>
  )
}

ReactDOM.render(<App />, document.getElementById("root"));

在根目录下新建public文件夹,pubilc文件夹下新建index.html文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>webpack5</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

三:配置HTML页面

html-webpack-plugin

创建一个html文件,并把Webpack打包后的静态资源插入到该HTML文件中

安装 html-webpack-plugin

yarn add --dev html-webpack-plugin

在webpack.config.js 文件中顶部,引入html-webpack-plugin

const htmlWebpackPlugin = require("html-webpack-plugin");

1646359322(1).png

在模块中配置插件的规则

new htmlWebpackPlugin({
    filename: "index.html",
    template: path.resolve(__dirname, "./public/index.html"),
}),

1646359479(1).png

四:配置热更新

webpack-dev-server

webpack为我们提供了devServer配置,支持我们每次更新代码热重载

安装 webpack-dev-server

yarn add -D webpack-dev-server

在wepack.config.js 文件下,创建devServer对象

devServer: { // 服务
        // 当使用 [HTML5 History API] 时,任意的 `404` 响应被替代为 `index.html`
        historyApiFallback: true,
        open: true, // 自动打开浏览器
        // 默认为true
        hot: true,
        // 是否开启代码压缩
        compress: true,
        // 启动的端口
        port: 9000,
 },

在package.json 新增调试命令

 "scripts": {
    "start": "webpack serve",
    "build": "webpack"
  },

打开终端,执行npm start

1646359859(1).png

成功运行,一个简易的react Webpack5已经配置好了

清空每次打包后dist残留的文件

yarn add -D clean-webpack-plugin

每次打包后,磁盘会残留之前打包的文件,每次打包前需要清除这些文件

安装 yarn add -D clean-webpack-plugin

yarn add -D clean-webpack-plugin

在webpack.config.js 文件的顶部引入clean-webpack-plugin 插件

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

在plugins 中,启用插件

 new CleanWebpackPlugin(),

1646360122(1).png

五:配置图片和字体

assets模块是webpack5自带,不用下载

// 图片
{
   test: /\.(png|jpe?g|svg|gif)$/,
   type: "asset/inline",
},
// 字体
{
   test: /\.(eot|ttf|woff|woff2)$/,
   type: "asset/resource",
   generator: {
      filename: "fonts/[hash][ext][query]",
   },
},

1646360343(1).png

六:配置路径别名

在webpack.config.js 文件下新建resolve对象

resolve: { // 别名
   alias: {
   "@": path.resolve(__dirname, "./src"),
   },
   mainFiles: ["index", "main"],
},

七:JS压缩

webpack5 自带最新的 terser-webpack-plugin

在webpack.config.js文件的顶部引入terser-webpack-plugin模块

const TerserPlugin = require("terser-webpack-plugin");

在webpack.config.js文件下 新建optimization对象,进行如下配置

new TerserPlugin({
    parallel: 4, // 并发数量
    terserOptions: {
      parse: {
      ecma: 8,
      },
      compress: {
      ecma: 5,
      warnings: false,
      comparisons: false,
      inline: 2,
      },
      mangle: {
      safari10: true,
      },
      output: {
      ecma: 5,
      comments: false,
      scii_only: true,
      },
   },
}),

1646360731(1).png

八:CSS的配置

配置CSS文件的支持,这里配置是对less支持,如果要支持sass支持,将less改为sass即可

  • postcss-loader
  • css-loader
  • MiniCssExtractPlugin
  • MiniCssExtractPlugin
  • style-loader

postcss-loader

postcss-loader 同时支持直接在loader中配置规则选项,也支持单独建立文件配置,这里我们选择单独使用文件进行配置:

安装后续用到的插件

yarn add -D cssnano autoprefixer@latest postcss-loader postcss
yarn add less less-loader --dev

新建一个postcss.config文件在根目录下

// 单独文件配置插件postcss-loader的规则
// 此处使用到 autoprefixer  cssnano 两个插件
// autoprefixer   为CSS内容添加浏览器厂商前缀兼容
// cssnano        尽可能小的压缩CSS代码
module.exports = {
    plugins: [
      require('autoprefixer'),
      require('cssnano')({
        preset: 'default',
      }),
    ],
}

1646361472(1).png

css-loader

解析CSS文件中的@import/require

安装css-loader

yarn add -D css-loader

在module模块中增加如下规则

// CSS和Less
{
 test: /\.(sa|sc|le|c)ss$/,
 use: [
       {
        loader: MiniCssExtractPlugin.loader,
        },
        "css-loader",
        "postcss-loader",
   // 当解析antd.less,必须写成下面格式,否则会报Inline JavaScript is not enabled错误
        { 
        loader: "less-loader", 
        options: { lessOptions: { javascriptEnabled: true } }},
  ],
},

1646361730(1).png

MiniCssExtractPlugin

为每个包含CSS 的 JS 文件创建一个 CSS 文件。它支持按需加载 CSS 和 SourceMaps

MiniCssExtractPlugin 和 style-loader 的区别

  • style-loader 是将CSS 插入到HTML的头部文件中
  • MiniCssExtractPlugin 是将拆分生成CSS 形成单独的CSS文件

安装 MiniCssExtractPlugin

yarn add -D mini-css-extract-plugin

在webpack.config.js文件顶部引入模块

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

在插件模块中开启插件

 // 开启压缩CSS插件
 new MiniCssExtractPlugin({
     filename: "assets/[name].css",
 }),

1646361941(1).png

九:编译进度条

progress-bar-webpack-plugin

查看编译进度

安装 progress-bar-webpack-plugin

yarn add progress-bar-webpack-plugin --dev

在文件的顶部引入对应的模块

// 编译进度条
const ProgressBarPlugin = require('progress-bar-webpack-plugin')

在插件规则中开启编译进度条插件

new ProgressBarPlugin({
    format: `:msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`
 })

1646362177(1).png

十:根据不同环境,拆分webpack.config.js文件

webpack-merge

使用 webpack-marge 合并通用配置和特定环境配置

安装 webpack-merge

yarn add webpack-merge --dev

在根目录下新建config文件夹,新建webpack.common, webpack.dev, webpack.pre

webpack.common

// webpack-merge
// 使用 webpack-marge 合并通用配置和特定环境配置
// yarn add webpack-merge --dev

const path = require('path')
const htmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // css抽离
const chalk = require('chalk')
const ProgressBarPlugin = require('progress-bar-webpack-plugin') // 编译进度条
module.exports = {
  resolve: {
    // 配置路径别名
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
    mainFiles: ['index', 'main'],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: 'babel-loader',
      },
      {
        test: /\.(le|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
          },
          'css-loader',
          'postcss-loader',
          // 当解析antd.less,必须写成下面格式,否则会报Inline JavaScript is not enabled错误
          { loader: 'less-loader', options: { lessOptions: { javascriptEnabled: true } } },
        ],
      },
      {
        test: /\.(png|jpe?g|svg|gif)$/,
        type: 'asset/inline',
      },
      {
        test: /\.(eot|ttf|woff|woff2)$/,
        type: 'asset/resource',
        generator: {
          filename: 'fonts/[hash][ext][query]',
        },
      },
    ],
  },
  plugins: [
    new htmlWebpackPlugin({
      filename: 'index.html',
      template: path.resolve(__dirname, '../public/index.html'),
    }),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: 'assets/[name].css',
    }),
    // 进度条
    new ProgressBarPlugin({
      format: `  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)`,
    }),
  ],
}

webpack.dev

const { merge } = require('webpack-merge')
const common = require('./webpack.common')
module.exports = merge(common, {
  mode: 'development',
  // 开发工具,开启 source map,编译调试
  devtool: 'eval-cheap-module-source-map',
  cache: {
    type: 'filesystem', // 使用文件缓存
  },
  entry: './src/index.jsx',
  devServer: {
    historyApiFallback: true,
    open: true, // 自动打开页面
    // 默认为true
    hot: true,
    // 是否开启代码压缩
    compress: true,
    // 启动的端口
    port: 8888,
  },
})

webpack.pre

const TerserPlugin = require('terser-webpack-plugin') // js压缩
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') // css压缩
const { merge } = require('webpack-merge')
const common = require('./webpack.common')

module.exports = merge(common, {
  mode: 'production',
  entry: './src/index.jsx',
  output: {
    path: __dirname + '/../dist',
    // [contenthash:8] - 本应用打包输出文件级别的更新,导致输出文件名变化
    filename: '[name]-[contenthash:8].js',
    // 编译前清除目录
    clean: true,
  },
  //terser-webpack-plugin 默认开启了 parallel: true 配置,并发运行的默认数量: os.cpus().length - 1 ,
  //  配置的 parallel 数量为 4,使用多进程并发运行压缩以提高构建速度。
  optimization: {
    // 通过配置 optimization.runtimeChunk = true,为运行时代码创建一个额外的 chunk,减少 entry chunk 体积,提高性能。
    // runtimeChunk: true,
    minimizer: [
      new TerserPlugin({
        parallel: 4,
        terserOptions: {
          parse: {
            ecma: 8,
          },
          compress: {
            ecma: 5,
            warnings: false,
            comparisons: false,
            inline: 2,
          },
          mangle: {
            safari10: true,
          },
          output: {
            ecma: 5,
            comments: false,
            ascii_only: true,
          },
        },
      }),
      new CssMinimizerPlugin({
        parallel: 4,
      }),
    ],
  },
})

修改package.json 文件中的调试命令

"scripts": {
    "start": "webpack serve --config config/webpack.dev.js",
    "build": "webpack --config config/webpack.prd.js"
 },

1646362718(1).png

一个简易的React 项目的环境就这样搭建结束了