webpack5手写 react 脚手架

257 阅读3分钟

前言

自己从事教学很长时间了,也使用react很长时间了,今天来实现下, 手写webpack脚手架,看一下,是如何实现的

1. 初始化目录

新建一个文件夹demo,用来存放项目。

先初始化项目

yarn init -y

安装webpack依赖

yarn add webpack webpack-cli webpack-dev-server

项目需要webpack作为构建工具,webpack-cli是webpack运行必须的脚手架,webpack-dev-server是可以启动开发者服务器, 如下图

image.png

接下来根目录新建config文件夹,用来存放webpack配置文件,新建public文件夹,存放资源,新建src文件夹,存放源代码。

image.png

2.配置webpack

因为项目运行有两种环境:开发和生产,所以我们在config目录下新建三个文件

  • webpack.config.js 公共配置
  • webpack.dev.js 开发配置
  • webpack.prod.js 生产配置

设置启动脚本,找到根目录package.json文件添加脚本。 这里我们需要使用node的自定义的环境变量NODE_ENV来区分不同的环境,但是不同系统操作是不一样的, 所以这里需要安装一个插件cross-env来处理不同环境问题

yarn add cross-env

build 打包启动命令 cross-env NODE_ENV=production (设置生产环境) webpack (打包) --conifg 指定配置文件

start 启动开发服务器 同上

 "scripts": {
    "build": "cross-env NODE_ENV=production webpack --config ./config/webpack.config.js",
    "start": "cross-env NODE_ENV=development webpack serve --config ./config/webpack.config.js"
  }

2-1 mode 模式

webpack 会根据 mode 设置当前的一些默认配置, 根据我们启动时候,设置的NODE_ENV的值,动态设置mode的模式。production 生产。 development 开发

const path = require('path')
module.exports = {
  // 模式
  mode: process.env.NODE_ENV === 'production' ? 'production': 'development',
}

2-2 entry 入口

webpack启动必须设置至少一个入口文件, 我们的入口文件在src/index.js

const path = require('path')

module.exports = {
  // 模式
  mode: process.env.NODE_ENV === 'production' ? 'production': 'development',
  // 入口
  entry: path.resolve(__dirname, '../src/index.js'),
}

执行打包命令 yarn build

image.png 默认生成的是dist目录

image.png 里面的main.js就是打包之后的代码

2-3 设置启动模版

一般我们是需要一个模版的html文件的,这里我们使用插件 html-webpack-plugin 来指定模版

// webpack.config.js
const path = require('path')
// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 模式
  mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
  // 入口
  entry: path.resolve(__dirname, '../src/index.js'),
  // 插件
  plugins: [new HtmlWebpackPlugin({
    // 指定模版 
    template: path.resolve(__dirname, '../public/index.html')
  })],
}

在入口文件src/index.js 输出打印

// src/index.js
console.log('我是入口文件')

在模版public/index.html 修改内容

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <!-- 添加节点 -->
  <div id="app">111</div>
</body>

</html>

打包执行 yarn build, 运行dist/index.html image.png

2-4 解析jsx 配置loader

安装 react react-dom 插件, 修改src/index.jsx

// src/index.js
import React from 'react';
import { createRoot } from 'react-dom/client';

const app = document.querySelector('#app')

const root = createRoot(app)

root.render(<div>1231231</div>)

打包项目, 会报错

image.png 这里会提示模块解析失败,原因是我们没有配置对应的loader去解析js文件。接下来要配置loader。 打包webpack官网, 查看babel-loader。 (什么是loader, loader是用来配置解析文件的。)

image.png 这里注意版本问题,楼主是webpack5的版本, 需要下载的babel8或者9都可以,我这里下载的是9的版本. babel-loader

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

配置webpack

// webpack.config.js
const path = require('path')
// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  // 模式
  mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
  // 入口
  entry: path.resolve(__dirname, '../src/index.jsx'),
  /******************************************************/
  // 模块
  module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-react']
            }
          }
        }
      ]
  },
  /******************************************************/
  // 插件
  plugins: [new HtmlWebpackPlugin({
    // 指定模版 
    template: path.resolve(__dirname, '../public/index.html')
  })],
}

这时候项目就可以正常启动了, 测试下, yarn start

2-5 拆分配置文件

目前, 我们所有的配置文件都在webpack.config.js中,接下来, 进行拆分两个环境的配置文件,首先删除原先在webpack.config.js中配置的mode字段,分别在webpack.dev.js和webpack.prod.js中添加对应的配置

// webpack.dev.js
// webpack.dev.js
module.exports = {
  mode: 'development',
  // 开发服务器配置
  devServer: {
    // 自动打开浏览器
    open: true
  }
}
module.exports = {
  mode: 'production'
}

安装插件 webpack-merge, 用来合并webpack配置。

yarn add webpack-merge

修改 webpack.config.js 代码, 在module.exports中合并配置代码

// 引入模块
const devConfig = require('./webpack.dev')
const prodConfig = require('./webpack.prod')
const { merge } = require('webpack-merge')

image.png 完整代码

// webpack.config.js
const path = require('path')
// 引入模块
const devConfig = require('./webpack.dev')
const prodConfig = require('./webpack.prod')
const { merge } = require('webpack-merge')
// 引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = merge({
  // 入口
  entry: path.resolve(__dirname, '../src/index.jsx'),
  /******************************************************/
  // 模块
  module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-react']
            }
          }
        }
      ]
  },
  /******************************************************/
  // 插件
  plugins: [new HtmlWebpackPlugin({
    // 指定模版 
    template: path.resolve(__dirname, '../public/index.html')
  })],
}, process.env.NODE_ENV === 'production' ? prodConfig : devConfig)