React 18.2.0 源码打包

一、React源码地址

GitHub:React

二、参考文章

sourcemap实战-生成react源码sourcemap
Rollup中文文档
JavaScript Source Map 详解
全网最优雅的 React 源码调试方式

三、打包操作
  1. 安装依赖
// 全局安装yarn
npm i -g yarn
// 源码项目目录下执行yarn安装依赖
yarn
  1. 修改后的build.js 文件
'use strict';const rollup = require('rollup');
const babel = require('rollup-plugin-babel');
const commonjs = require('rollup-plugin-commonjs');
const prettier = require('rollup-plugin-prettier');
const replace = require('rollup-plugin-replace');
const stripBanner = require('rollup-plugin-strip-banner');
const chalk = require('chalk');
const resolve = require('rollup-plugin-node-resolve');
const fs = require('fs');
const argv = require('minimist')(process.argv.slice(2));
const Modules = require('./modules');
const Bundles = require('./bundles');
const Stats = require('./stats');
const sizes = require('./plugins/sizes-plugin');
const useForks = require('./plugins/use-forks-plugin');
const Packaging = require('./packaging');
const {asyncRimRaf} = require('./utils');
const codeFrame = require('babel-code-frame');
const Wrappers = require('./wrappers');// 默认以实验模式进行构建。如果通过环境变量设置了发布渠道,则检查其是否为 "experimental"。
const __EXPERIMENTAL__ = true
// Errors in promises should be fatal.
let loggedErrors = new Set();
process.on('unhandledRejection', err => {if (loggedErrors.has(err)) {// No need to print it twice.process.exit(1);}throw err;
});const { UMD_DEV } = Bundles.bundleTypes;const {getFilename} = Bundles;// 处理路由参数,拆分出需要打包的文件的文件名
function parseRequestedNames(names, toCase) {let result = [];for (let i = 0; i < names.length; i++) {let splitNames = names[i].split(',');for (let j = 0; j < splitNames.length; j++) {let name = splitNames[j].trim();if (!name) {continue;}if (toCase === 'uppercase') {name = name.toUpperCase();} else if (toCase === 'lowercase') {name = name.toLowerCase();}result.push(name);}}return result;
}const requestedBundleTypes = argv.type? parseRequestedNames([argv.type], 'uppercase'): [];// 解析脚本输入的文件名
const requestedBundleNames = parseRequestedNames(argv._, 'lowercase');// 用于处理非 ES2015 代码,如 Flow 类型、类属性、对象扩展运算符等)转换为兼容旧环境的代码,同时避免引入额外运行时依赖,为 Closure Compiler 的优化做准备。
// Non-ES2015 stuff applied before closure compiler.
const babelPlugins = [// These plugins filter out non-ES2015.// 移除Flow的类型定义'@babel/plugin-transform-flow-strip-types',// 转换类属性(class properties),将类中的属性定义转换为对象字面量形式,支持使用更简洁的语法定义类属性。['@babel/plugin-proposal-class-properties', {loose: true}],// 兼容在函数末尾加逗号的写法'syntax-trailing-function-commas',// These use loose mode which avoids embedding a runtime.// TODO: Remove object spread from the source. Prefer Object.assign instead.['@babel/plugin-proposal-object-rest-spread',{loose: true, useBuiltIns: true},],['@babel/plugin-transform-template-literals', {loose: true}],// TODO: Remove for...of from the source. It requires a runtime to be embedded.'@babel/plugin-transform-for-of',// TODO: Remove array spread from the source. Prefer .apply instead.['@babel/plugin-transform-spread', {loose: true, useBuiltIns: true}],'@babel/plugin-transform-parameters',// TODO: Remove array destructuring from the source. Requires runtime.['@babel/plugin-transform-destructuring', {loose: true, useBuiltIns: true}],// Transform Object spread to shared/assignrequire('../babel/transform-object-assign'),
];// Babel 插件数组 ,其核心作用是定义一组用于将现代 JavaScript 代码(ES6+)转换为 ES5 兼容语法的插件集合,确保构建产物能在不支持新特性的旧版浏览器中正常运行。
const babelToES5Plugins = [// These plugins transform DEV mode. Closure compiler deals with these in PROD.'@babel/plugin-transform-literals','@babel/plugin-transform-arrow-functions','@babel/plugin-transform-block-scoped-functions','@babel/plugin-transform-shorthand-properties','@babel/plugin-transform-computed-properties',['@babel/plugin-transform-block-scoping', {throwIfClosureRequired: true}],
];// 获取babel的配置
function getBabelConfig(updateBabelOptions,bundleType,packageName,externals,isDevelopment,bundle
) {const canAccessReactObject =packageName === 'react' || externals.indexOf('react') !== -1;let options = {exclude: '/**/node_modules/**',babelrc: false,configFile: false,presets: [],plugins: [...babelPlugins],};if (isDevelopment) {options.plugins.push(...babelToES5Plugins,// Turn console.error/warn() into a custom wrapper[require('../babel/transform-replace-console-calls'),{shouldError: !canAccessReactObject,},]);}if (updateBabelOptions) {options = updateBabelOptions(options);}return options;
}// 获取rollup的配置
function getRollupOutputOptions(outputPath,format,globals,globalName,bundleType
) {return {file: outputPath,format,globals,freeze: true,interop: false,name: globalName,sourcemap: true,esModule: false,};
}// 禁止fbjs的导入
function forbidFBJSImports() {return {name: 'forbidFBJSImports',resolveId(importee, importer) {if (/^fbjs\//.test(importee)) {throw new Error(`Don't import ${importee} (found in ${importer}). ` +`Use the utilities in packages/shared/ instead.`);}},};
}function getPlugins(entry,externals,updateBabelOptions,filename,packageName,bundleType,globalName,moduleType,pureExternalModules,bundle
) {const forks = Modules.getForks(bundleType, entry, moduleType, bundle);const isUMDBundle =bundleType === UMD_DEV ||bundleType === UMD_PROD ||bundleType === UMD_PROFILING;return [// Shim any modules that need forking in this environment.useForks(forks),// Ensure we don't try to bundle any fbjs modules.forbidFBJSImports(),// Use Node resolution mechanism.resolve({skip: externals,}),// Remove license headers from individual modulesstripBanner({exclude: 'node_modules/**/*',}),// Compile to ES2015.babel(getBabelConfig(updateBabelOptions,bundleType,packageName,externals,true,bundle)),// Remove 'use strict' from individual source files.// {//   transform(source) {//     return source.replace(/['"]use strict["']/g, '');//   }, // },// Turn __DEV__ and process.env checks into constants.replace({__DEV__: 'true',__PROFILE__: 'true',__UMD__: isUMDBundle ? 'true' : 'false','process.env.NODE_ENV':"'production'",__EXPERIMENTAL__,// Enable forked reconciler.// NOTE: I did not put much thought into how to configure this.__VARIANT__: bundle.enableNewReconciler === true,}),// The CommonJS plugin *only* exists to pull "art" into "react-art".// I'm going to port "art" to ES modules to avoid this problem.// Please don't enable this for anything else!isUMDBundle && entry === 'react-art' && commonjs(),// Add the whitespace back if necessary.// License and haste headers, top-level `if` blocks.// {//   renderChunk(source) {//     return Wrappers.wrapBundle(//       source,//       bundleType,//       globalName,//       filename,//       moduleType,//       bundle.wrapWithModuleBoundaries//     );//   },// },// Record bundle size.sizes({getSize: (size, gzip) => {const currentSizes = Stats.currentBuildResults.bundleSizes;const recordIndex = currentSizes.findIndex(record =>record.filename === filename && record.bundleType === bundleType);const index = recordIndex !== -1 ? recordIndex : currentSizes.length;currentSizes[index] = {filename,bundleType,packageName,size,gzip,};},}),].filter(Boolean);
}// 1,将所有的打包格式和所有打包的bundle进行叉乘,得到所有的组合方式
// 2. 遍历所有的组合方式进行打包
// 3. 打包前过滤掉 组合中bundleType和bundle不匹配的
// 4. 
// 是否跳过构建
function shouldSkipBundle(bundle, bundleType) {// 判断bundle支持的类型中是否包含需要打包成的产物的类型const shouldSkipBundleType = bundle.bundleTypes.indexOf(bundleType) === -1;if (shouldSkipBundleType) {return true;}// 判断脚本调用参数是否满足:bundleType 中包含脚本入参传入的格式,也就是该bundle支持所需要打包的格式if (requestedBundleTypes.length > 0) {const isAskingForDifferentType = requestedBundleTypes.every(requestedType => bundleType.indexOf(requestedType) === -1);if (isAskingForDifferentType) {return true;}}// 输入的文件名if (requestedBundleNames.length > 0) {// If the name ends with `something/index` we only match if the// entry ends in something. Such as `react-dom/index` only matches// `react-dom` but not `react-dom/server`. Everything else is fuzzy// search.// bundle的入口文件const entryLowerCase = bundle.entry.toLowerCase() + '/index.js';// const isAskingForDifferentNames = requestedBundleNames.every(requestedName => {const matchEntry = entryLowerCase.indexOf(requestedName) !== -1;if (!bundle.name) {return !matchEntry;}const matchName =bundle.name.toLowerCase().indexOf(requestedName) !== -1;return !matchEntry && !matchName;});if (isAskingForDifferentNames) {return true;}}return false;
}function resolveEntryFork(resolvedEntry) {// Pick which entry point fork to use:// .modern.fb.js// .classic.fb.js// .fb.js// .stable.js// .experimental.js// .jsconst resolvedForkedEntry = resolvedEntry.replace('.js','.experimental.js');if (fs.existsSync(resolvedForkedEntry)) {return resolvedForkedEntry;}// Just use the plain .js one.return resolvedEntry;
}// 创建bundle.js 执行创建逻辑
async function createBundle(bundle, bundleType) {// 判断类型是否匹配if (shouldSkipBundle(bundle, bundleType)) {return;}const filename = getFilename(bundle, bundleType);const logKey =chalk.white.bold(filename) + chalk.dim(` (${bundleType.toLowerCase()})`);const format = 'umd';const packageName = Packaging.getPackageName(bundle.entry);let resolvedEntry = resolveEntryFork(require.resolve(bundle.entry));const shouldBundleDependencies =bundleType === UMD_DEV ||bundleType === UMD_PROD ||bundleType === UMD_PROFILING;const peerGlobals = Modules.getPeerGlobals(bundle.externals, bundleType);let externals = Object.keys(peerGlobals);if (!shouldBundleDependencies) {const deps = Modules.getDependencies(bundleType, bundle.entry);externals = externals.concat(deps);}const importSideEffects = Modules.getImportSideEffects();const pureExternalModules = Object.keys(importSideEffects).filter(module => !importSideEffects[module]);const rollupConfig = {input: resolvedEntry,treeshake: {pureExternalModules,},external(id) {const containsThisModule = pkg => id === pkg || id.startsWith(pkg + '/');const isProvidedByDependency = externals.some(containsThisModule);if (!shouldBundleDependencies && isProvidedByDependency) {if (id.indexOf('/src/') !== -1) {throw Error('You are trying to import ' +id +' but ' +externals.find(containsThisModule) +' is one of npm dependencies, ' +'so it will not contain that source file. You probably want ' +'to create a new bundle entry point for it instead.');}return true;}return !!peerGlobals[id];},onwarn: handleRollupWarning,plugins: getPlugins(bundle.entry,externals,bundle.babel,filename,packageName,bundleType,bundle.global,bundle.moduleType,pureExternalModules,bundle),output: {externalLiveBindings: false,freeze: false,interop: false,esModule: false,},};const mainOutputPath = Packaging.getBundleOutputPath(bundleType,filename,packageName);const rollupOutputOptions = getRollupOutputOptions(mainOutputPath,format,peerGlobals,bundle.global,bundleType);console.log(`${chalk.bgYellow.black(' BUILDING ')} ${logKey}`);try {// rollup api 打包const result = await rollup.rollup(rollupConfig);await result.write(rollupOutputOptions);} catch (error) {console.log(`${chalk.bgRed.black(' OH NOES! ')} ${logKey}\n`);handleRollupError(error);throw error;}console.log(`${chalk.bgGreen.black(' COMPLETE ')} ${logKey}\n`);
}function handleRollupWarning(warning) {if (warning.code === 'UNUSED_EXTERNAL_IMPORT') {const match = warning.message.match(/external module '([^']+)'/);if (!match || typeof match[1] !== 'string') {throw new Error('Could not parse a Rollup warning. ' + 'Fix this method.');}const importSideEffects = Modules.getImportSideEffects();const externalModule = match[1];if (typeof importSideEffects[externalModule] !== 'boolean') {throw new Error('An external module "' +externalModule +'" is used in a DEV-only code path ' +'but we do not know if it is safe to omit an unused require() to it in production. ' +'Please add it to the `importSideEffects` list in `scripts/rollup/modules.js`.');}// Don't warn. We will remove side effectless require() in a later pass.return;}if (warning.code === 'CIRCULAR_DEPENDENCY') {// Ignored} else if (typeof warning.code === 'string') {// This is a warning coming from Rollup itself.// These tend to be important (e.g. clashes in namespaced exports)// so we'll fail the build on any of them.console.error();console.error(warning.message || warning);console.error();process.exit(1);} else {// The warning is from one of the plugins.// Maybe it's not important, so just print it.console.warn(warning.message || warning);}
}function handleRollupError(error) {loggedErrors.add(error);if (!error.code) {console.error(error);return;}console.error(`\x1b[31m-- ${error.code}${error.plugin ? ` (${error.plugin})` : ''} --`);console.error(error.stack);if (error.loc && error.loc.file) {const {file, line, column} = error.loc;// This looks like an error from Rollup, e.g. missing export.// We'll use the accurate line numbers provided by Rollup but// use Babel code frame because it looks nicer.const rawLines = fs.readFileSync(file, 'utf-8');// column + 1 is required due to rollup counting column start position from 0// whereas babel-code-frame counts from 1const frame = codeFrame(rawLines, line, column + 1, {highlightCode: true,});console.error(frame);} else if (error.codeFrame) {// This looks like an error from a plugin (e.g. Babel).// In this case we'll resort to displaying the provided code frame// because we can't be sure the reported location is accurate.console.error(error.codeFrame);}
}async function buildEverything() {if (!argv['unsafe-partial']) {await asyncRimRaf('build');}let bundles = [];// eslint-disable-next-line no-for-of-loops/no-for-of-loopsfor (const bundle of Bundles.bundles) {bundles.push([bundle, UMD_DEV],);}// 创建bundle.js// eslint-disable-next-line no-for-of-loops/no-for-of-loopsfor (const [bundle, bundleType] of bundles) {await createBundle(bundle, bundleType);}await Packaging.copyAllShims();await Packaging.prepareNpmPackages();console.log(Stats.printResults());Stats.saveResults();
}buildEverything();
  1. 运行打包脚本
yarn build react/index,react-dom/index --type=UMD_DEV

执行之后在控制台能看到打包结果:请添加图片描述
打包产物在项目根目录下build文件夹:
在这里插入图片描述
4. 在react项目中使用打包的产物

  1. 获取创建的react项目的webpack配置:
    npm run eject
    
  2. 在config/webpack.config.js里面修改配置项: 在这里插入图片描述
  3. 将打包的产物react.development.js react.development.js.map react-dom.development.js react-dom.development.js.map复制到react项目的public目录下
  4. 运行react项目
    yarn start
    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86370.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UniApp 开发第一个项目

UniApp 开发第一个项目全流程指南,涵盖环境搭建、项目创建、核心开发到调试发布,结合最新实践整理而成,适合零基础快速上手: 🧰 一、环境准备(5分钟) 安装开发工具 HBuilderX(官方推荐IDE):下载 App 开发版,安装路径避免中文或空格 微信开发者工具(调试小程序必备…

Web项目开发中Tomcat10+所需的jar包

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl 项目背景 Web项目中使用低版本Tomcat时常用的jar包如下&#xff1a; javax.servlet-apijavax.ejb-apijavax.jms-apijavax.json-api 当Web项目使用Tomcat10的版本时&#…

网络安全就业方向与现实发展分析:机遇、挑战与未来趋势

网络安全行业的战略地位与就业背景 在数字经济蓬勃发展的今天&#xff0c;网络安全已从技术分支演变为关乎国家安全、企业存亡和个人隐私的核心领域。根据国家网信办数据显示&#xff0c;2025年我国网络安全人才缺口达200万人&#xff0c;较2023年增长33%。这一现象源于三重驱…

iOS runtime随笔-消息转发机制

运行时的消息转发分三步, 当你调用了没有实现的方法时, 有机会通过runtime的消息转发机制补救一下 resolveInstanceMethod/resolveClassMethod 这里可以动态去创建方法来解决CrashforwardingTargetForSelector ​​​​​第一步未解决, 就会走到这里, 可以给出一个Target去转发…

vue3用js+css实现轮播图(可调整堆叠程度)

先看效果 html <divclass"outer"style"width: 650px;background: #fff;box-shadow: 0px 0px 8px rgba(0, 0, 0, 0.1);border-radius: 15px;margin: 0 10px 15px 5px;">//这里用的是svg-icon,需要的可自行替换为其他图片<svg-iconid"btn_l&q…

Three.js项目实战:从零搭建小米SU7三维汽车

大家如果有过购车的经验&#xff0c;肯定会先从网站上收集车辆的信息&#xff0c;比如懂车帝&#xff0c;汽车之家&#xff0c;这些网站上逼真的看车效果是如何实现的呢&#xff0c;这节课带你从0-1快速的手搓一个看车小项目。 懂车帝官网 效果 视频教程和笔记 大家可以下方小…

Android13 永久关闭SELinux 权限

永久关闭 SeLinux 在cmdline中增加参数androidboot.selinuxpermissive&#xff1b; 芯片: QCM6115 版本: Android 13 kernel: msm-4.19 ~/temp_code/SLM927D_LA.UM.9.15$ git diff device/qcom/bengal/BoardConfig.mk diff --git a/device/qcom/bengal/BoardConfig.mk b…

Linux创建DHCP服务

Linux可作为DHCP服务端使用&#xff0c;为同一个网络下的其它机器动态分配ip。在一些情况下&#xff0c;可以起到很大的作用。 二级标题 安装dnsmasq # ubuntu sudo apt update -y sudo apt install -y dnsmasq# centos sudo yum install -y dnsmasq修改配置文件 sudo vim …

汽车4G-TBOX智能终端 汽车国标GB/T 32960协议

汽车国标GB/T 32960协议4G TBOX是一种广泛应用于车联网的设备&#xff0c;下面将从不同方面为你详细介绍。 移动管家汽车4G-TBOX智能终端定义与用途 4G TBOX是基于车联网技术智能服务系统中的采集终端。以车云网的4G TBOX_CC750为例&#xff0c;它为整个智能服务系统提供GPS/…

JavaEE-Mybatis初阶

什么是MyBatis MyBatis是⼀款优秀的 持久层 框架&#xff0c;⽤于简化JDBC的开发。 MyBatis本是 Apache的⼀个开源项⽬iBatis&#xff0c;2010年这个项⽬由apache迁移到了google code&#xff0c;并 且改名为MyBatis 。2013年11⽉迁移到Github 创建项目时添加依赖 上面有…

记一次jvm机器问题定位经历

背景 开发过程中发现机器指标异常&#xff0c;端口也hang住无响应&#xff0c;端口返回为timeout&#xff0c;对应探活检测也失败了。 现象 在st测试环节&#xff0c;突然每隔一段时间新接口就hang住无响应&#xff0c;观察机器监控也发现端口探活失败&#xff0c;看机器指标…

【机器学习深度学习】张量基本操作

目录 一、张量基本操作 1.1 执行代码 1.2 运行结果 1.3 代码解析 ✅ 1. 创建张量&#xff08;tensor、randn、zeros&#xff09; ✅ 2. 索引与切片&#xff08;类似 NumPy&#xff09; ✅ 3. 形状变换&#xff08;reshape、转置、压缩&#xff09; ✅ 4. 数学运算&#x…

【微信小程序】8、获取用户当前的地理位置

1、获取当前的地理位置 获取当前的地理位置、速度。当用户离开小程序后&#xff0c;此接口无法调用。开启高精度定位&#xff0c;接口耗时会增加&#xff0c;可指定 highAccuracyExpireTime 作为超时时间。 注意&#xff1a; 地图相关使用的坐标格式应为 gcj02。高频率调用会…

Jenkins 常用定时构建脚本

Jenkins 常用定时构建脚本 Jenkins 使用 cron 风格的语法来配置定时构建任务&#xff0c;以下是常用的定时构建脚本示例和说明&#xff1a; 基本语法 Jenkins 定时构建使用五个字段表示时间&#xff0c;格式为&#xff1a; MINUTE HOUR DOM MONTH DOWMINUTE - 分钟 (0-59)H…

ActiveMQ漏洞复现

以下内容均在nextcyber靶场环境中完成&#xff0c;请勿用于非法途径&#xff01; ActiveMQ 反序列化漏洞&#xff08;CVE-2015-5254&#xff09; Apache ActiveMQ是美国阿帕奇&#xff08;Apache&#xff09;软件基金会所研发的一套开源的消息中间件&#xff0c;它支持Java消息…

环保处理设备远程运维管理解决方案

在环保产业蓬勃发展的当下&#xff0c;环保处理设备厂商面临着愈发激烈的市场竞争。为助力环保处理设备厂商在竞争中脱颖而出&#xff0c;御控工业智能网关打造了一套完善的PLC数据采集设备运维管理平台解决方案。此方案凭借其独特优势&#xff0c;能为环保处理设备厂商带来显著…

嵌入式学习笔记DAY43(ARM架构)

一、RAM分类 sram&#xff08;静态随机存取存储器&#xff09;&#xff1a; 原理&#xff1a;使用晶体管来存储二进制数据0和1&#xff0c;通过双稳态电路&#xff08;由多个晶体管组成&#xff09;来保持数据状态&#xff0c;只要持续供电&#xff0c;数据就能稳定保存。数据读…

2025国际无人机应用及防控大会四大技术专题深度解析

2025国际无人机应用及防控大会四大技术专题深度解析 2025国际无人机应用及防控大会四大技术专题深度解析1 无人机系统技术专题技术特点与应用领域国内领军企业及案例风险挑战与发展方向 2 测控与通信导航技术专题技术创新与应用突破领先企业及解决方案现存问题与发展趋势 3 任务…

DD3118S:USB3.0+Type-c双头TF/SD二合一高速0TG多功能手机读卡器ic

DD3118S封装是QFN42, GL3224封装是QFN32 &#xff0c;设计同样一款3.0读卡方案&#xff0c;GL3213S需要电容、电阻外围器件一起要29颗&#xff0c;而DD3118S只需要13颗&#xff0c;方案精简且设计简单 DD3118S支持USB3.0Type-c双头TF/SD二合一 &#xff0c;高速0TG多功能手机读…

如何在FastAPI中玩转GitHub认证,让用户一键登录?

title: 如何在FastAPI中玩转GitHub认证,让用户一键登录? date: 2025/06/22 09:11:47 updated: 2025/06/22 09:11:47 author: cmdragon excerpt: GitHub第三方认证集成通过OAuth2.0授权码流程实现,包含用户跳转GitHub认证、获取授权码、交换访问令牌及调用API获取用户信息四…