美文网首页
Webpack5 + React18 项目搭建

Webpack5 + React18 项目搭建

作者: 一个好昵称X | 来源:发表于2023-11-27 19:14 被阅读0次

    记录 React 从 0 到 1 搭建过程

    1、安装 node 环境

    搭建前端项目前,首先要安装本机的 node 环境,直接去 node 官网下载对应的安装包手动安装即可。 官网传送门;
    安装完成后,在命令行工具执行以下命令,查看是否安装成功:

        node -v
        npm -v
    
    image.png

    2、项目搭建

    2.1、初始化项目

    新建文件夹 react-demo;
    进入 react-demo 内,在命令行工具内执行 npm init ,初始化项目。
    按照提示操作完成后,文件夹内会生成一个 package.json 文件。


    image.png
    2.2、安装 webpack

    执行一下命令安装 webpack,推荐使用 yarn 安装。
    使用 yarn 前需要先全局安装:

      npm i -g yarn
    

    安装webpack:

      yarn add webpack webpack-cli
    

    安装完后会在项目根目录生成一个 yarn.lock 文件,该文件用来锁定当前依赖的版本号,后续再执行install 时,会直接安装该文件内的依赖版本,不会再自动更新 package.json 中的依赖版本。
    要想更新 package.json 中的依赖版本需要执行如下命令覆盖:

      yarn add xxx@xxx
    
    2.3、初始化项目结构

    在src目录下,新增 index.js,作为项目的入口文件,也是 webpack 配置的入口文件;
    根目录下新增 src 文件夹,用于存放源码;
    根目录下新增 config 文件夹,用于存放 webpack 和 项目相关配置的文件;

    在 config 文件加下新增 webpack.config.js 文件,在该文件内加入如下内容,配置 webpack 基本信息

      const path = require('path');
    
      module.exports = {
        mode: 'development', // 指定 webpack 打包环境
        entry: './src/index.js', // 项目的入口文件,路径相对于项目根路径
        output: {                       
          filename: 'bundle.js', // 打包输出的文件名,实际项目中需要按一定规则动态生成
          path: path.resolve(__dirname, '../dist') // 打包完成后输出的路径,这里的路径针对的是当前目录
        }
      };
    

    在根目录 index.js 文件中,加入一个打印日志,用来测试打包是否成功:


    image.png

    配置 package.json 内的 script 命令,用来执行打包操作:
    增加如下命令:

      "build": "webpack --config ./config/webpack.config.js",
    
    image.png

    在命令行工具内 执行如下命令,来进行打包:

      yarn build
    

    打包完成后,在根目录会生成一个 dist 目录,里面有 bundle.js 文件,即打包后的文件。


    image.png

    打包过程中可能出现的报错:

    • invalid or unexpected token
      产生该问题的原因可能有以下几种;
    1. webpack 配置文件配置错误或者是语法错误
    2. 缺少loader
      某些非 js 文件的资源,缺少对应的 loader ,也可能会导致此问题。
    3. 文件编码问题
      排除问题时,可以尝试是否文件编码的问题,增加 webpack-encoding-plugin 配置,修改编码。
      首先安装 webpack-encoding-plugin 依赖,
      yarn add webpack-encoding-plugin
    

    在 webpack 配置文件中增加如下配置:

      const EncodingPlugin = require('webpack-encoding-plugin');
      
      // 增加 plugin 配置
      plugins: [
        new EncodingPlugin({
          encoding: 'utf-8'
        })
      ]
    

    重新打包

    2.4 增加核心配置

    安装 babel 核心依赖,这样依赖会将 ES5+ 的语法转换成 ES5,目前ES5+的语法还不能直接在浏览器编译,因此需要安装这些依赖对ES5+的代码进行一个转换。

      yarn add babel-loader @babel/core @babel/preset-env @babel/preset-react
    

    依赖安装完成后,在项目根目录新建文件 .babelrc,并加入如下内容:

    {
      "presets": [ // 相当于插件集合,不需要在 plugins 中再配置多个插件
        [
          "@babel/preset-env", {
            "useBuiltIns": "entry",    //如果用了@babel/polyfill的话,配置这个属性可以将@babel/polyfill按需引入
            "corejs": 2
          }
        ],
        "@babel/preset-react"
      ],
      "plugins": []
    }
    
    module.exports = babelConfig;
    

    修改 webpack.config.js,新增module,配置 babel-loader:

      module: {
        rules: [
          // 配置babel-loader
          {
            test: /\.(js|jsx)$/,
            use: ["babel-loader"],
            include: path.join(__dirname, "../src"),
            exclude: /node_modules/,
          },
        ],
      },
    

    配置完成后,在入口文件内新增 es6+ 的内容,并重新打包,测试配置是否成功。

    上述配置完成后,因为 babel 只会转换 es6 语法,而不会转换新的 api (如 promise,generator 函数等),让新的 api 生效的方法是使用传统的 polyfill,为此需要安装 @babel/polyfill 这个模块。

    安装 @babel/polyfill

      yarn add @babel/polyfill 
    

    @babel/polyfill 安装完成后不再需要进行额外的配置。

    安装完 @babel/polyfill 之后,还需要安装以下3个库,来实现按需加载的效果:

      yarn add @babel/runtime @babel/plugin-transform-runtime @babel/plugin-syntax-dynamic-import @babel/plugin-proposal-class-properties
    

    这几个库的作用可参考知乎文章
    一文谈完前端项目中的Babel配置

    上述依赖安装完成后,增加 babel 相关配置,在 .babelrc 文件中增加以下配置:

      plugins: [
        "@babel/plugin-syntax-dynamic-import",
        "@babel/plugin-proposal-class-properties",
        "@babel/plugin-transform-runtime"
      ]
    

    入口文件内,新增 Promise 代码,重新打包,测试打包效果。

      const promise = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve('sync log');
        }, 1000);
      });
    
      promise.then(res => {
        console.log(res);
      });
    

    新增sass/less 等css预处理器解析配置
    安装以下依赖

       yarn add stylus stylus-loader less less-loader sass-loader node-sass css-loader style-loader
    

    在webpack 配置文件中,配置解析器, 新增loader:

        // 配置css预处理器
        {
          test: /\.less$/,
          use: [
            "style-loader",
            "css-loader",
            "less-loader",
          ],
        },
    

    配置完成后,根目录下新增 index.less 文件,加入样式配置:

      @primary-color: #29BEDB;
    
      div {
        color: @primary-color;
        font-size: 14px;
        font-weight: 600;
      }
    

    在 index.js 入口文件中,引入新增的样式文件,重新打包,查看打包效果。

    在使用到 css3 的某些新特性时,为了适应不同浏览器的兼容性,需要为不同的浏览器增加不同的前缀,此时就需要用到 postcss-loader 来为css代码自动添加前缀。
    安装依赖

      yarn add postcss-loader autoprefixer cssnano
    

    配置loader:

          {
            test: /\.less$/,
            use: [
              "style-loader",
              "css-loader",
              {
                loader: "postcss-loader",
                options: {
                  postcssOptions: {
                    plugins: [
                      require("autoprefixer"),
                      require("cssnano")
                    ],
                  },
                },
              },
              "less-loader",
            ],
          },
    

    配置静态资源解析

    在项目中用到的图片等资源,都需要配置相关的解析工具,安装如下依赖:

      yarn add file-loader url-loader
    

    file-loader可以用来帮助 webpack 打包处理一系列的图片文件。打包后的每张图片都会生成一个随机的 hash 值作为图片名;url-loader 封装了 file-loader,其工作原理:1、文件大小小于limit 数值,url-loader 将会把文件转为Base64;2、文件大小大于 limit,url-loader 会调用 file-loader 进行处理,参数也会直接传给file-loader。

    配置 loader,新增图片资源loader:

          //配置图片资源loader
          {
            test: /\.(jpg|png|jpeg|gif)$/,
            use: [
              {
                loader: "url-loader",
                options: {
                  limit: 1024,
                  fallback: {
                    loader: "file-loader",
                    options: {
                      name: "img/[name].[hash:8].[ext]",
                    },
                  },
                },
              },
            ],
          },
    

    配置完成后,在 src 目录下新增 assets 静态资源目录,在目录内放入一张图片,在入口文件 index.js 文件中引入图片,重新打包。

      const img = require('./assets/img/profile.jpg');
    

    打包完成后,可以看到在dist目录内生成一个新的 img 目录,里面即是用到的图片文件,说明打包成功。

    配置压缩js、css等文件,减小打包体积
    安装依赖:

      yarn add mini-css-extract-plugin
    

    在webpack配置文件中新增相关配置

      // 引入插件依赖
      const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    
      // plugins内 实例化插件 
      plugins: [
        // 实例化插件 MiniCssExtractPlugin
        new MiniCssExtractPlugin({
          filename: "css/[name].[contenthash].css",
          chunkFilename: "css/[id].[contenthash].css",
        }),
      ],
    
      // 配置loader, module内新增loader
      // 配置css压缩插件
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../",
            },
          },
          "css-loader",
        ],
      },
    

    配置完成后,在根目录新增 test.css 文件,在入口文件内引入,进行打包,查看效果。
    打包成功后会在 dist 目录内出现 css 文件目录。


    image.png

    该插件之后压缩 css 文件,原 less 文件还会继续打包到 js 文件内。

    抽离公共代码
    打包后的 js 、css 文件中会有很多公共代码,如果不将这些代码进行抽离,最后打包文件会变得很大,所以需要使用 SplitChunksPlugin 插件抽离公共代码,只需在 webpack 配置文件中加入如下配置:

      optimization: {
        // 抽离公共代码插件的配置
        splitChunks: {
          cacheGroups: {
            // 打包公共模块
            commons: {
              chunks: "initial", // 代码分割时默认对异步代码生效 async,all:所有代码有效,initial:同步代码有效
              minChunks: 2, // 分割之前模块在块与块之间共享的最小次数
              minSize: 20000, // 提取公共部分的最小的大小(以字节为单位)
              name: "common", // 设为 false 将保持块的相同名称,因此不会不必要地更改名称(生产版本推荐)
            },
          },
        },
      },
    

    配置解析器Resolve
    Resolvers 解析器=用于告诉 webpack 去哪些目录下查找引用的模块,默认值是["node_modules"]。

    webpack 配置文件下,新增如下内容:

      resolve: {
        extensions: [".js", ".jsx"], // 引入 js jsx文件时,引入路径不需携带文件后缀
        // 设置别名,@ 直接指向 src 目录
        alias: {
          "@": path.resolve(__dirname, "../src"),
        },
      },
    

    ** 配置热更新 **
    新增如下依赖

      yarn add webpack-dev-server html-webpack-plugin  
    

    webpack-dev-server 用于热更新,html-webpack-plugin 用于动态的将打包后的 css、js文件加入到 html 中,相关配置如下:

    在 plugins 内新增 HtmlWebpackPlugin 实例化

        // 引入html模板插件
        const HtmlWebpackPlugin = require('html-webpack-plugin');
    
        //实例化Html模板模块
        // 不指定模板会在dist目录自动生成一个html文件
        new HtmlWebpackPlugin({
          template: path.resolve(__dirname, "../index.html"),
        }),
    
        // 配置 devServer
        devServer: {
          // 配置热更新模块
          static: {
            directory: path.join(__dirname, "public"),
          },
          compress: true,
          hot: true,
          port: 3001,
        },
    

    在根目录新增 index.html 文件,加入如下内容

      <!DOCTYPE html>
      <html>
        <head>
          <meta charset="utf-8">
          <title>Webpack Demo</title>
          <meta name="viewport" content="width=device-width, initial-scale=1">
        </head>
        <body>
          <div id="root"></div>
        </body>
      </html>
    

    在 package.json 文件中 script 内新增启动命令:

      "start": "webpack-dev-server --config ./config/webpack.config.js",
    

    控制台执行 yarn start 启动项目。

    删除上一次的打包结果及记录
    安装依赖

       yarn add clean-webpack-plugin
    

    clean-webpack-plugin 帮我们在每次打包时,清除上一次打包的内容。
    配置如下,直接实例化插件即可:

      // 引入插件
      const { CleanWebpackPlugin } = require("clean-webpack-plugin");
    
      // 实例化插件
      new CleanWebpackPlugin(),
    

    3、集成 React

    安装React、react-dom
    首先安装 react、react-dom 依赖

      yarn add react react-dom
    

    在入口文件内挂载 React

      import React from "react";
      import ReactDOM from "react-dom/client";
    
      import App from "@/App";
    
      // v18 的新方法
      const root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(
        <React.StrictMode>
          <App />
        </React.StrictMode>
      );
    

    在 src 目录下新增 App.js 文件:

      import React from "react";
    
      const App = () => {
        return <div> React18 + Webpack5 from 0 to 1 </div>;
      };
    
      export default App;
    

    重新 yarn start 启动项目,启动成功


    image.png

    安装react-router-dom

      yarn add react-router-dom 
    

    依赖安装完成后,在 src 目录下新增 routes 目录,用来存放页面组件代码。
    在 routes 下新增 List.js,Detail.js 两个文件。


    image.png

    两个文件内分别加入不同的内容
    List.js

      import React from 'react';
    
      export default function List() {
        return (
          <>
            this is list page.
          </>
        )
      }
    

    Detail.js

      import React from "react";
    
      export default function Detail() {
        return <div style={{color: 'red'}}>this is detail page.</div>;
      }
    

    此时在 src 目录下新增 config 目录,config目录下新增 routers.js 文件,用于存放页面路由。
    routers.js 文件内加入如下内容:

      // 存放页面路由
      import List from "@/routes/List";
      import Detail from "@/routes/Detail";
    
      // 存放页面路由
      const routes = [
        {
          path: "/",
          component: List,
          exact: true,
        },
        {
          path: "/detail",
          component: Detail,
        },
      ];
    
      export default routes;
    

    修改入口文件 index.js 如下:

      import React from "react";
      import ReactDOM from "react-dom/client";
      import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
    
      import routes from "./config/routers";
    
      // v18 的新方法
      const root = ReactDOM.createRoot(document.getElementById("root"));
      root.render(
        <React.StrictMode>
          <Router>
            <Link to="/">列表</Link>
            &nbsp;&nbsp;
            <Link to="/detail">详情</Link>
    
            <Routes>
              {routes.map((item, key) => {
                if (item.exact) {
                  return (
                    <Route
                      exact
                      path={item.path}
                      element={<item.component />}
                      key={key}
                    />
                  );
                } else {
                  return (
                    <Route path={item.path} element={<item.component />} key={key} />
                  );
                }
              })}
            </Routes>
          </Router>
        </React.StrictMode>
      );
    

    启动项目,可点击列表 或详情 加载对应的内容:


    image.png

    相关文章

      网友评论

          本文标题:Webpack5 + React18 项目搭建

          本文链接:https://www.haomeiwen.com/subject/ohlgwdtx.html