从零搭建Webpack5-react脚手架(附源码)
webpack5
近期终于有时间和精力专注于公司技术基础建设了,于是一开始,将公司的Saas
系统改造成了微前端模式,解决了历史遗留的一部分问题
接着,想着webpack5
已经发布这么久了,该在生产环境用起来了,也顺势想推动微前端
、webpack5
、vite
在业内的普及率,没看过我之前文章的朋友可以在文末找找,干货真的很多
正式开始
webpack5升级后,有哪些改变?
通过持久化缓存提高性能
采用更好的持久化缓存算法和默认行为
通过优化 Tree Shaking 和代码生成来减小Bundle体积(干掉了nodejs的polyfill)
提高 Web 平台的兼容性
清除之前为了实现 Webpack4 没有不兼容性变更导致的不合理 state
尝试现在引入重大更改来为将来的功能做准备,以使我们能够尽可能长时间地使用 Webpack 5
新增Module Federation(联邦模块)
搭建指南
推荐大家使用我在我们公司(
深圳明源云空间
)做的脚手架,给大家一键生成项目模板,这样大家在看本文的时候会得到更好的提升
生成模板步骤:
npm i ykj-cli -g
ykj init webpack5 (这里选择通用项目模板)
cd webpack5
yarn
yarn dev
开始搭建
首先新建文件夹,使用yarn初始化项目
mkdir webpack5-demo
cd webpack5-demo
yarn init webpack5-demo
...一路回车
下载
webpack webpack-cli
最新版本:
yarn add webpack@next webpack-cli@next -D
然后安装
React react-dom
17版本的库
yarn add react@17.0.0 react-dom@17.0.0 --save
接着安装
react
官方热更新推荐的库
yarn add react-refresh -D
安装
less css style标签 postcss
等样式处理的库(mini-css-extract-plugin
要安装@next
版本的)
yarn add less less-loader css-loader style-loader mini-css-extract-plugin@next -D
安装相关
babel
依赖
yarn add core-js@3.9.0 @babel/core@next babel-loader@next @babel/preset-env@next -D
babel
具体要哪些配置,建议大家参考我的模板里面
完成了依赖的准备工作,开始搭建项目
项目根目录创建
config
文件夹,用于放置webpack
配置文件config
文件夹下新建四个文件
paths.js//存放路径
webpack.base.js //基础配置
webpack.dev.js//开发配置
webpack.prod.js//生产配置
在
paths
文件内,用变量记录几个关键目录:
const path = require('path');module.exports = {// 源码目录src: path.resolve(__dirname, '../src'),// 构建后的资源产物文件夹build: path.resolve(__dirname, '../dist'),// 静态资源public: path.resolve(__dirname, '../public'),
};
编写基础
webpack.base.js
配置文件,引入依赖
//webpack.base.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const paths = require('./paths');
编写
entry
和output
字段:
entry: paths.src + 'index.tsx',output: {path: path.resolve(__dirname, '../dist'),filename: '[name].[contenthash].js',publicPath: '',},
这里要注意的是,
webpack5
对contenthash
算法进行了优化,这里可以在chunkhash
和contenthash
中选择一个,建议contenthash
编写基础
loader
配置:
module: {rules: [{use: 'babel-loader',test: /\.(ts|tsx)$/,exclude: /node_modules/,},{use: ['style-loader', 'css-loader', 'less-loader'],test: /\.(css|less)$/,},{type: 'asset',test: /\.(png|svg|jpg|jpeg|gif)$/i,},],},
这里要注意的是:
webpack5
对于资源,类似:图片、字体文件等,可以用内置的asset
去处理,不用url-loader
和file-loader
了
接着,由于项目需要配置别名和省略后缀名,我们先配置
resolve
字段(我是TypeScript+React技术栈):
resolve: {extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],alias: {'@': paths.src,'@c': paths.src + '/components','@m': paths.src + '/model','@s': paths.src + '/services','@t': paths.src + '/types',},},
插件的话,由于是基础配置,只要一个
clean、html
的插件即可
plugins: [new CleanWebpackPlugin(),new HtmlWebpackPlugin({template: './public/index.html',}),],
在项目根目录新建文件
babel.config.js
const { argv } = require('yargs');
const isDev = argv.mode === 'development';
const plugins = [['const-enum',{transform: 'constObject',},],'lodash','@babel/plugin-transform-runtime',//支持import 懒加载'@babel/plugin-syntax-dynamic-import','@babel/plugin-transform-async-to-generator','transform-class-properties',['import',{libraryName: 'antd',libraryDirectory: 'es',style: true, // or 'css'},'antd',],['import',{libraryName: 'ykj-ui',libraryDirectory: 'lib/components',style: true, // or 'css'},'ykj-ui',],
];
module.exports = (api) => {api.cache(true);return {presets: [['@babel/preset-env',{corejs: 3.9,useBuiltIns: 'usage',},],['@babel/preset-react',{runtime: 'automatic',},],'@babel/preset-typescript',],plugins: isDev ? [...plugins, 'react-refresh/babel'] : [...plugins],};
};
这样,我们的基础
webpack
配置就好了,捋一捋先:
用babel处理
tsx ts
和es
高阶语法用
loader
处理less
语法用插件处理了
html
和负责清理工作用
resolve
字段配置了别名和省略文件后缀用内置的
asset
处理了静态文件,例如图片等
编写webpack.dev.js
开发配置
引入依赖
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const { HotModuleReplacementPlugin } = require('webpack');
const { merge } = require('webpack-merge');
const common = require('./webpack.base');
先引入了热更新、合并配置、基础配置、官方react热更新依赖
接着编写配置
const devConfig = {mode: 'development',devServer: {port: 3000,contentBase: '../dist',open: true,hot: true,},target: 'web',plugins: [new HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin()],devtool: 'eval-cheap-module-source-map',
};module.exports = merge(common, devConfig);
注意:这里要设置
target: 'web'
才会有热更新效果
devtool在开发模式最佳实践是:
eval-cheap-module-source-map
这样,我们的开发模式配置就搭建好了,只要在public
文件夹下编写一个index.html
,就可以跟之前一样,开始写react
项目了
开始编写webpack.prod.js
生产配置
引入依赖:
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { merge } = require('webpack-merge');
const common = require('./webpack.base');
生产环境要抽离
css
标签,所以这里针对less和css要做特殊处理,一个是postcss
处理样式兼容性问题,一个是MiniCssExtractPlugin.loader
:
const prodConfig = {mode: 'production',devtool: 'hidden-source-map',module: {rules: [{test: /\.(css|less)$/,use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'less-loader'],},],},optimization: {splitChunks: {chunks: 'all',name: false,},},plugins: [new MiniCssExtractPlugin()],
};
module.exports = merge(common, prodConfig);
这样生产的配置也编写好了
生产环境devtool最佳实践是:
hidden-source-map
编写scripts命令
"build": "webpack --config config/webpack.prod.js --mode production",
"dev": "webpack serve --config config/webpack.dev.js --mode development",
注意:热更新以前是
webpack-dev-server
,现在是webpack serve
!!!
配置代码质量管控流程
新增依赖
yarn add lint-staged @commitlint/cli @commitlint/config-conventional -D
编写代码、提交检测流程
"husky": {"hooks": {"pre-commit": "lint-staged","commit-msg": "commitlint -E HUSKY_GIT_PARAMS"}},"lint-staged": {"src/**/*.{js,jsx,ts,tsx,json,css,less,md}": ["prettier --write","eslint --fix","git add"]},"browserslist": ["ie >= 10","ff >= 30","chrome >= 34","safari >= 8","opera >= 23"]
}
新增
eslint
配置:
//.eslintrc.js
module.exports = {root: true,parserOptions: {ecmaVersion: 7,sourceType: 'module',},parser: '@typescript-eslint/parser',plugins: ['typescript', 'react'],env: {browser: true,node: true,es6: true,},rules: {semi: ['error', 'always'], // 该规则强制使用一致的分号'no-unused-vars': 'off', // 禁止未使用过的变量'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 debugger'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', //生产环境禁用 console'default-case': ['warn', { commentPattern: '^no default$' }], //要求 Switch 语句中有 Default'dot-location': ['warn', 'property'], // 强制在点号之前或之后换行eqeqeq: ['error', 'allow-null'], //要求使用 === 和 !=='new-parens': 'warn', //要求调用无参构造函数时带括号'no-caller': 'error', // 禁用 caller 或 callee'no-const-assign': 'error', //不允许改变用 const 声明的变量'no-dupe-args': 'error', //禁止在 function 定义中出现重复的参数'no-dupe-class-members': 'error', //不允许类成员中有重复的名称'no-dupe-keys': 'warn', //禁止在对象字面量中出现重复的键'no-extend-native': 'warn', //禁止扩展原生对象'no-extra-bind': 'warn', //禁止不必要的函数绑定'no-fallthrough': 'error', //禁止 case 语句落空'no-func-assign': 'warn', //禁止对 function 声明重新赋值'no-implied-eval': 'error', //禁用隐式的 eval()'no-label-var': 'error', //禁用与变量同名的标签'no-loop-func': 'error', //禁止循环中存在函数'no-mixed-operators': ['warn',{groups: [['&', '|', '^', '~', '<<', '>>', '>>>'],['==', '!=', '===', '!==', '>', '>=', '<', '<='],['&&', '||'],['in', 'instanceof'],],allowSamePrecedence: false,},], //禁止混合使用不同的操作符'no-multi-str': 'warn', //禁止多行字符串 (需要多行时用\n)'no-native-reassign': 'warn', //禁止重新分配本地对象'no-obj-calls': 'warn', //禁止将全局对象当作函数进行调用'no-redeclare': 'error', //禁止重新声明变量'no-script-url': 'warn', //禁用 Script URL'no-shadow-restricted-names': 'warn', //关键字不能被遮蔽'no-sparse-arrays': 'warn', //禁用稀疏数组'no-this-before-super': 'warn', //在构造函数中禁止在调用 super()之前使用 this 或 super'no-undef': 'error', //禁用未声明的变量'no-unexpected-multiline': 'warn', //禁止使用令人困惑的多行表达式'no-use-before-define': ['warn',{functions: false,classes: false,variables: false,},], //禁止定义前使用'no-with': 'error', //禁用 with 语句radix: 'error', //禁用函数内没有 yield 的 generator 函数'rest-spread-spacing': ['warn', 'never'], //强制限制扩展运算符及其表达式之间的空格'react/jsx-no-undef': 'error', //在 JSX 中禁止未声明的变量'react/no-direct-mutation-state': 'error', //禁止 this.state 的直接变化'react/jsx-uses-react': 'warn', //防止 React 被错误地标记为未使用'no-alert': 0, //禁止使用alert confirm prompt'no-duplicate-case': 2, //switch中的case标签不能重复'no-eq-null': 2, //禁止对null使用==或!=运算符'no-inner-declarations': [2, 'functions'], //禁止在块语句中使用声明(变量或函数)'no-iterator': 2, //禁止使用__iterator__ 属性'no-negated-in-lhs': 2, //in 操作符的左边不能有!'no-octal-escape': 2, //禁止使用八进制转义序列'no-plusplus': 0, //禁止使用++,--'no-self-compare': 2, //不能比较自身'no-undef-init': 2, //变量初始化时不能直接给它赋值为undefined'no-unused-expressions': 2, //禁止无用的表达式'no-useless-call': 2, //禁止不必要的call和apply'init-declarations': 0, //声明时必须赋初值'prefer-const': 0, //首选const'use-isnan': 2, //禁止比较时使用NaN,只能用isNaN()'vars-on-top': 2, //var必须放在作用域顶部},
};
单元测试
新增命令:
"test": "jest", //进行测试
"test-c": "jest --coverage" //生成测试报告
安装jest
等依赖:
yarn add jest-environment-enzyme ts-jest@next enzyme enzyme-adapter-react-17 enzyme-to-json @types/enzyme @types/enzyme-adapter-react-17 @types/enzyme-to-json -D
新建文件夹 test
编写第一个单元测试,引入依赖:
import App from '../src/App';
import { mount, shallow } from 'enzyme';
import React from 'react';
import toJson from 'enzyme-to-json'; //做快照
然后就可以愉快的开始写单元测试了哦
这样,一个
webpack5
的脚手架就搭建好了,webpack
内置的一些东西,可以让我们省去很多配置,看起来会更简单
????往期我的原创好文推荐
微前端的部署最佳实践(k8s + ingress)
微前端框架是怎么导入加载子应用的 【3000字精读】
熬夜准备的一个React项目升级Vite的指南
尤雨溪的5KB petite-vue源码解析
熬夜写的解析掘金新版本编辑器源码
Vite和Webpack的核心差异
CSS是如何发起攻击的?
使用require.context,实现去路由中心化管理
一行代码实现display"过渡动画"原理
在React中实现和Vue一样舒适的keep-alive
Node.js结合ProtoBuffer,从零实现一个redis! [一万字]
使用Node.js驱动Redis,实现一个消息队列!
8000字总结的前端性能优化
前端工程师学Docker ?看这篇就够了 【零基础入门 原创】
深度:手写一个WebSocket协议 [7000字]
精读:10个案例让你彻底理解React hooks的渲染逻辑
原创:如何自己实现一个简单的webpack
5000字解析:前端五种跨平台技术
如何优化你的超大型React应用 【原创精读】
前端面试官:你知道source-map的原理是什么吗?
原创:带你从零看清Node源码createServer和负载均衡整个过程
Express version 4.17核心源码解析
通过Node.js的Cluster模块源码,深入PM2原理
大前端时代,浅谈JavaScript开发重型跨平台应用以及架构
为什么我们要熟悉这些通信协议?【精读】
看完两件事
如果你觉得这篇内容对你挺有启发,我想邀请你帮我几件小事
1.点个「在看、赞、关注」,让更多人也能看到这篇内容(点了「在看」,bug -1 ????)
2.关注微信公众号「前端巅峰」,让我持续为你推送精选好文
我是Peter谭,一位小厂前端开发工程师,喜欢搞架构,对性能优化,跨平台开发有一定研究,还喜欢做自媒体,区块链。欢迎关注我
从零搭建Webpack5-react脚手架(附源码)相关推荐
- 【webpack系列】从零搭建 webpack4+react 脚手架(四)
经过三个章节的学习,你已经学会搭建了一个基于webpack4的react脚手架.如果要更改配置,比如,你希望把编译后的js文件和css文件等单独放dist下的static目录下,你想想,是不是有点麻烦 ...
- 从零搭建 webpack4+react 脚手架
前提条件 在开始之前,请确保安装了 Node.js 的最新版本.建议使用 Node.js 最新的长期支持版本(LTS - Long Term Support).如果你使用旧版本,你可能遇到各种问题,因 ...
- 关于构建umi+dva+ant react项目 附源码
刚刚入门react,通过视频学习,做一个简单的react表格功能实现.功能满足对表格数据进行增删改,数据来源于后端接口.交互也与后端接口进行! 话不多说,直接看效果! 接口设置了30%的概率报错,出现 ...
- SpringBoot之从零搭建网站(可提供源码)
前言 为什么想要搭建这个工作室? 我还记得,在大学的时候,我们往常一样的在学习过着大学生活,同往常一样的解决这某个bug,不停地问度娘,很巧的碰到了一个同行在他的博客中完美的记录了搭建网站的过程,随后 ...
- 关于美团:零基础搭建获利的美团饿了么优惠券CPS小程序附源码
关于美团:零基础搭建获利的美团饿了么优惠券CPS小程序附源码 下面是无裂变版本的搭建教程. 源码地址:http://y.mybei.cn 部署步骤 部署后台,填资料 登录后台 http://q.myb ...
- 零基础搭建获利的美团饿了么优惠券CPS小程序(附源码)
1.先上图 2.前言 某天下午,我正在公司认真的写着代码,突然我的手机弹了一个通知,我赶紧抓起手机看看(给自己一个摸鱼的理由) 让我看看到底是谁发消息打扰我认真的工作啊. 害,原来是某个群转发了一个外 ...
- arcgis开发 多版本之间如何兼容_arcgis api 4.x for js 结合 react 入门开发系列初探篇(附源码下载)...
你还在使用 JQuery 或者 Dojo 框架开发 arcgis api 4.x for js 吗?想试试模块化开发吗?随着前端技术的发展,arcgis api 4.x for js 也有了结合 re ...
- 从零搭建Spring Boot脚手架:开篇以及技术选型1
1. 前言 目前Spring Boot已经成为主流的Java Web开发框架,熟练掌握Spring Boot并能够根据业务来定制Spring Boot成为一个Java开发者的必备技巧,但是总是零零碎碎 ...
- springboot项目结构_从零搭建Spring Boot脚手架(1):开篇以及技术选型
1. 前言 目前Spring Boot已经成为主流的Java Web开发框架,熟练掌握Spring Boot并能够根据业务来定制Spring Boot成为一个Java开发者的必备技巧,但是总是零零碎碎 ...
最新文章
- 蚂蚁森林合种计划(2020.12.26更新,7天有效)
- 微隔离的红蔷薇在湾区创见的舞台绽放
- 第十二章 支持向量机-机器学习老师板书-斯坦福吴恩达教授
- 使用jmeter 设计流程发起测试
- 《C++ Primer》14.3.1节练习
- AMPL 简单运输模型
- linux与windows共享(四)
- idea常用快捷键以及自定义快捷键
- 【C++】算法集锦(11):敏感词过滤算法(DFA)
- iphone编程资源站
- JQuery 判断浏览器及其版本
- Vulnhub_MoneyBox
- no theme named ‘sphinx_rtd_theme‘ found (missing theme.conf?)
- 可供量、现有量、承诺量
- Cocos2d-x Lua库函数剖析(二)cocos2d
- 怎样用计算机打出Abc,智能ABC输入法中的一些使用技巧
- LENOVO_WIN7_UM_32_ZH_CN_RDVD.iso
- 【项目管理】如何确定项目预算?
- JavaScript-BOM
- 角色所在服务器正在维护,梦幻西游角色所在服务器,角色所在服务器如何删除...