前言
自己从事教学很长时间了,也使用react很长时间了,今天来实现下, 手写webpack脚手架,看一下,是如何实现的
1. 初始化目录
新建一个文件夹demo,用来存放项目。
先初始化项目
yarn init -y
安装webpack依赖
yarn add webpack webpack-cli webpack-dev-server
项目需要webpack作为构建工具,webpack-cli是webpack运行必须的脚手架,webpack-dev-server是可以启动开发者服务器, 如下图
接下来根目录新建config文件夹,用来存放webpack配置文件,新建public文件夹,存放资源,新建src文件夹,存放源代码。
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
默认生成的是dist目录
里面的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
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>)
打包项目, 会报错
这里会提示模块解析失败,原因是我们没有配置对应的loader去解析js文件。接下来要配置loader。
打包webpack官网, 查看babel-loader。
(什么是loader, loader是用来配置解析文件的。)
这里注意版本问题,楼主是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')
完整代码
// 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)