Webpack: 并行构建
概述
受限于 Node.js 的单线程架构,原生 Webpack 对所有资源文件做的所有解析、转译、合并操作本质上都是在同一个线程内串行执行,CPU 利用率极低,因此,理所当然地,社区出现了一些以多进程方式运行 Webpack,或 Webpack 构建过程某部分工作的方案(从而提升单位时间利用率),例如:
- HappyPack:多进程方式运行资源加载(Loader)逻辑;
- Thread-loader:Webpack 官方出品,同样以多进程方式运行资源加载逻辑;
- Parallel-Webpack:多进程方式运行多个 Webpack 构建实例;
- TerserWebpackPlugin:支持多进程方式执行代码压缩、uglify 功能。
这些方案的核心设计都很类似:针对某种计算任务创建子进程,之后将运行所需参数通过 IPC 传递到子进程并启动计算操作,计算完毕后子进程再将结果通过 IPC 传递回主进程,寄宿在主进程的组件实例,再将结果提交给 Webpack。
使用 HappyPack
HappyPack 能够将耗时的文件加载(Loader)操作拆散到多个子进程中并发执行,子进程执行完毕后再将结果合并回传到 Webpack 进程,从而提升构建性能。不过,HappyPack 的用法稍微有点难以理解,需要同时:
- 使用
happypack/loader代替原本的 Loader 序列; - 使用
HappyPack插件注入代理执行 Loader 序列的逻辑。
基本用法:
-
安装依赖:
yarn add -D happypack -
将原有
loader配置替换为happypack/loader,如:module.exports = {// ...module: {rules: [{test: /\.js$/,use: "happypack/loader",// 原始配置如:// use: [// {// loader: 'babel-loader',// options: {// presets: ['@babel/preset-env']// }// },// 'eslint-loader'// ]},],}, }; -
创建
happypack插件实例,并将原有 loader 配置迁移到插件中,完整配置:const HappyPack = require("happypack");module.exports = {// ...module: {rules: [{test: /\.js$/,use: "happypack/loader",// 原始配置如:// use: [// {// loader: 'babel-loader',// options: {// presets: ['@babel/preset-env']// }// },// 'eslint-loader'// ]},],},plugins: [new HappyPack({// 将原本定义在 `module.rules.use` 中的 Loader 配置迁移到 HappyPack 实例中loaders: [{loader: "babel-loader",option: {presets: ["@babel/preset-env"],},},"eslint-loader",],}),], };
配置完毕后,再次启动 npx webpack 命令,即可使用 HappyPack 的多进程能力提升构建性能。以 Three.js 为例,该项目包含 362 份 JS 文件,合计约 3w 行代码:

开启 HappyPack 前,构建耗时大约为 11000ms 到 18000ms 之间,开启后耗时降低到 5800ms 到 8000ms 之间,提升约47%。
上述示例仅演示了使用 HappyPack 加载单一资源类型的场景,实践中我们还可以创建多个 HappyPack 插件实例,来加载多种资源类型 —— 只需要用 id 参数做好 Loader 与 Plugin 实例的关联即可,例如:
const HappyPack = require('happypack');module.exports = {// ...module: {rules: [{test: /\.js?$/,// 使用 `id` 参数标识该 Loader 对应的 HappyPack 插件示例use: 'happypack/loader?id=js'},{test: /\.less$/,use: 'happypack/loader?id=styles'},]},plugins: [new HappyPack({// 注意这里要明确提供 id 属性id: 'js',loaders: ['babel-loader', 'eslint-loader']}),new HappyPack({id: 'styles',loaders: ['style-loader', 'css-loader', 'less-loader']})]
};
这里的重点是:
js、less资源都使用happypack/loader作为唯一加载器,并分别赋予id = 'js' | 'styles'参数;- 创建了两个
HappyPack插件实例并分别配置id属性,以及用于处理 js 与 css 的loaders数组; - 启动后,
happypack/loader与HappyPack插件实例将通过id值产生关联,以此实现对不同资源执行不同 Loader 序列。
上面这种多实例模式虽然能应对多种类型资源的加载需求,但默认情况下,HappyPack 插件实例 自行管理 自身所消费的进程,需要导致频繁创建、销毁进程实例 —— 这是非常昂贵的操作,反而会带来新的性能损耗。
为此,HappyPack 提供了一套简单易用的共享进程池接口,只需要创建 HappyPack.ThreadPool 对象,并通过 size 参数限定进程总量,之后将该例配置到各个 HappyPack 插件的 threadPool 属性上即可,例如:
const os = require('os')
const HappyPack = require('happypack');
const happyThreadPool = HappyPack.ThreadPool({// 设置进程池大小size: os.cpus().length - 1
});module.exports = {// ...plugins: [new HappyPack({id: 'js',// 设置共享进程池threadPool: happyThreadPool,loaders: ['babel-loader', 'eslint-loader']}),new HappyPack({id: 'styles',threadPool: happyThreadPool,loaders: ['style-loader', 'css-loader', 'less-loader']})]
};
使用 HappyPack.ThreadPool 接口后,HappyPack 会预先创建好一组工作进程,所有插件实例的资源转译任务会通过内置的 HappyThread 对象转发到空闲进程做处理,避免频繁创建、销毁进程。
最后,我们再来看看 HappyPack 的执行流程:
核心步骤:
happlypack/loader接受到转译请求后,从 Webpack 配置中读取出相应 HappyPack 插件实例;- 调用插件实例的
compile方法,创建HappyThread实例(或从HappyThreadPool取出空闲实例); HappyThread内部调用child_process.fork创建子进程,并执行HappyWorkerChannel文件;HappyWorkerChannel创建HappyWorker,开始执行 Loader 转译逻辑;
中间流程辗转了几层,最终由 HappyWorker 类重新实现了一套与 Webpack Loader 相似的转译逻辑,代码复杂度较高,大家稍作了解即可。
HappyPack 虽然确实能有效提升 Webpack 的打包构建速度,但它有一些明显的缺点:
- 作者已经明确表示不会继续维护,扩展性与稳定性缺乏保障,随着 Webpack 本身的发展迭代,可以预见总有一天 HappyPack 无法完全兼容 Webpack;
- HappyPack 底层以自己的方式重新实现了加载器逻辑,源码与使用方法都不如 Thread-loader 清爽简单,而且会导致一些意想不到的兼容性问题,如
awesome-typescript-loader; - HappyPack 主要作用于文件加载阶段,并不会影响后续的产物生成、合并、优化等功能,性能收益有限。
使用 Thread-loader
Thread-loader 与 HappyPack 功能类似,都是以多进程方式加载文件的 Webpack 组件,两者主要区别:
- Thread-loader 由 Webpack 官方提供,目前还处于持续迭代维护状态,理论上更可靠;
- Thread-loader 只提供了一个 Loader 组件,用法简单很多;
- HappyPack 启动后会创建一套 Mock 上下文环境 —— 包含
emitFile等接口,并传递给 Loader,因此对大多数 Loader 来说,运行在 HappyPack 与运行在 Webpack 原生环境相比没有太大差异;但 Thread-loader 并不具备这一特性,所以要求 Loader 内不能调用特定上下文接口,兼容性较差。
说一千道一万,先来看看基本用法:
-
安装依赖:
yarn add -D thread-loader -
将 Thread-loader 放在
use数组首位,确保最先运行,如:module.exports = {module: {rules: [{test: /\.js$/,use: ["thread-loader", "babel-loader", "eslint-loader"],},],}, };
启动后,Thread-loader 会在加载文件时创建新的进程,在子进程中使用 loader-runner 库运行 thread-loader 之后的 Loader 组件,执行完毕后再将结果回传到 Webpack 主进程,从而实现性能更佳的文件加载转译效果。
以 Three.js 为例,使用 Thread-loader 前,构建耗时大约为 11000ms 到 18000ms 之间,开启后耗时降低到 8000ms 左右,提升约37%。
此外,Thread-loader 还提供了一系列用于控制并发逻辑的配置项,包括:
workers:子进程总数,默认值为require('os').cpus() - 1;workerParallelJobs:单个进程中并发执行的任务数;poolTimeout:子进程如果一直保持空闲状态,超过这个时间后会被关闭;poolRespawn:是否允许在子进程关闭后重新创建新的子进程,一般设置为false即可;workerNodeArgs:用于设置启动子进程时,额外附加的参数。
使用方法跟其它 Loader 一样,都是通过 use.options 属性传递,如:
module.exports = {module: {rules: [{test: /\.js$/,use: [{loader: "thread-loader",options: {workers: 2,workerParallelJobs: 50,// ...},},"babel-loader","eslint-loader",],},],},
};
不过,Thread-loader 也同样面临着频繁的子进程创建、销毁所带来的性能问题,为此,Thread-loader 提供了 warmup 接口用于前置创建若干工作子进程,降低构建时延,用法:
const threadLoader = require("thread-loader");threadLoader.warmup({// 可传入上述 thread-loader 参数workers: 2,workerParallelJobs: 50,},[// 子进程中需要预加载的 node 模块"babel-loader","babel-preset-es2015","sass-loader",]
);
执行效果与 HappyPack.ThreadPool 相似,此处不再赘述。
与 HappyPack 相比,Thread-loader 有两个突出的优点,一是产自 Webpack 官方团队,后续有长期维护计划,稳定性有保障;二是用法更简单。但它不可避免的也存在一些问题:
- 在 Thread-loader 中运行的 Loader 不能调用
emitAsset等接口,这会导致style-loader这一类加载器无法正常工作,解决方案是将这类组件放置在thread-loader之前,如['style-loader', 'thread-loader', 'css-loader']; - Loader 中不能获取
compilation、compiler等实例对象,也无法获取 Webpack 配置。
这会导致一些 Loader 无法与 Thread-loader 共同使用,大家需要仔细加以甄别、测试。
使用 Parallel-Webpack
Thread-loader、HappyPack 这类组件所提供的并行能力都仅作用于文件加载过程,对后续 AST 解析、依赖收集、打包、优化代码等过程均没有影响,理论收益还是比较有限的。对此,社区还提供了另一种并行度更高,以多个独立进程运行 Webpack 实例的方案 —— Parallel-Webpack,基本用法:
-
安装依赖:
yarn add -D parallel-webpack -
在
webpack.config.js配置文件中导出多个 Webpack 配置对象,如:module.exports = [{entry: 'pageA.js',output: {path: './dist',filename: 'pageA.js'} }, {entry: 'pageB.js',output: {path: './dist',filename: 'pageB.js'} }]; -
执行
npx parallel-webpack命令。
-
Parallel-Webpack 会为配置文件中导出的每个 Webpack 配置对象启动一个独立的构建进程,从而实现并行编译的效果。底层原理很简单,基本上就是在 Webpack 上套了个壳:
- 根据传入的配置项数量,调用
worker-farm创建复数个工作进程; - 工作进程内调用 Webpack 执行构建;
- 工作进程执行完毕后,调用
node-ipc向主进程发送结束信号。
- 根据传入的配置项数量,调用
-
这种方式在需要同时执行多份配置的编译时特别有效,但若配置文件本身只是导出了单个配置对象则意义不大。
-
为了更好地支持多种配置的编译,Parallel-Webpack 还提供了
createVariants函数,用于根据给定变量组合,生成多份 Webpack 配置对象,如:const createVariants = require('parallel-webpack').createVariants const webpack = require('webpack')const baseOptions = {entry: './index.js' }// 配置变量组合 // 属性名为 webpack 配置属性;属性值为可选的变量 // 下述变量组合将最终产生 2*2*4 = 16 种形态的配置对象 const variants = {minified: [true, false],debug: [true, false],target: ['commonjs2', 'var', 'umd', 'amd'] }function createConfig (options) {const plugins = [new webpack.DefinePlugin({DEBUG: JSON.stringify(JSON.parse(options.debug))})]return {output: {path: './dist/',filename: 'MyLib.' +options.target +(options.minified ? '.min' : '') +(options.debug ? '.debug' : '') +'.js'},plugins: plugins} }module.exports = createVariants(baseOptions, variants, createConfig) -
上述示例使用
createVariants函数,根据variants变量搭配出 16 种不同的minified、debug、target组合,最终生成如下产物:[WEBPACK] Building 16 targets in parallel [WEBPACK] Started building MyLib.umd.js [WEBPACK] Started building MyLib.umd.min.js [WEBPACK] Started building MyLib.umd.debug.js [WEBPACK] Started building MyLib.umd.min.debug.js[WEBPACK] Started building MyLib.amd.js [WEBPACK] Started building MyLib.amd.min.js [WEBPACK] Started building MyLib.amd.debug.js [WEBPACK] Started building MyLib.amd.min.debug.js[WEBPACK] Started building MyLib.commonjs2.js [WEBPACK] Started building MyLib.commonjs2.min.js [WEBPACK] Started building MyLib.commonjs2.debug.js [WEBPACK] Started building MyLib.commonjs2.min.debug.js[WEBPACK] Started building MyLib.var.js [WEBPACK] Started building MyLib.var.min.js [WEBPACK] Started building MyLib.var.debug.js [WEBPACK] Started building MyLib.var.min.debug.js -
虽然,parallel-webpack 相对于 Thread-loader、HappyPack 有更高的并行度,但进程实例之间并没有做任何形式的通讯,这可能导致相同的工作在不同进程 —— 或者说不同 CPU 核上被重复执行。
-
例如需要对同一份代码同时打包出压缩和非压缩版本时,在 parallel-webpack 方案下,前置的资源加载、依赖解析、AST 分析等操作会被重复执行,仅仅最终阶段生成代码时有所差异。
-
这种技术实现,对单 entry 的项目没有任何收益,只会徒增进程创建成本;但特别适合 MPA 等多 entry 场景,或者需要同时编译出 esm、umd、amd 等多种产物形态的类库场景。
并行压缩
Webpack4 默认使用 Uglify-js 实现代码压缩,Webpack5 之后则升级为 Terser —— 一种性能与兼容性更好的 JavaScript 代码压缩混淆工具,两种组件都原生实现了多进程并行压缩能力。
以 Terser 为例,TerserWebpackPlugin 插件默认已开启并行压缩,开发者也可以通过 parallel 参数(默认值为 require('os').cpus() - 1)设置具体的并发进程数量,如:
const TerserPlugin = require("terser-webpack-plugin");module.exports = {optimization: {minimize: true,minimizer: [new TerserPlugin({parallel: 2 // number | boolean})],},
};
上述配置即可设定最大并行进程数为 2。此外,Webpack4 所使用的 uglifyjs-webpack-plugin 也提供了类似的功能,用法与 Terser 相同,此处不再赘述。
总结
受限于 JavaScript 的单线程架构,Webpack 构建时并不能充分使用现代计算机的多核 CPU 能力,为此社区提供了若干基于多进程实现的并行构建组件,包括文中介绍的 HappyPack、Thread-loader、Parallel-Webpack、Terser。
-
对于 Webpack4 之前的项目,可以使用 HappyPack 实现并行文件加载;
-
Webpack4 之后则建议使用 Thread-loader;
-
多实例并行构建场景建议使用 Parallel-Webpack 实现并行;
-
生产环境下还可配合
terser-webpack-plugin的并行压缩功能,提升整体效率。 -
理论上,并行确实能够提升系统运行效率,但 Node 单线程架构下,所谓的并行计算都只能依托与派生子进程执行,而创建进程这个动作本身就有不小的消耗 —— 大约 600ms,对于小型项目,构建成本可能可能很低,引入多进程技术反而导致整体成本增加,因此建议大家按实际需求斟酌使用上述多进程方案。
-
可以思考,有没有可能使用 Node Worker 实现多线程形式的 Webpack 并行构建?社区是否已经有相关组件?与多进程相比,可能存在怎么样的优缺点?
相关文章:
Webpack: 并行构建
概述 受限于 Node.js 的单线程架构,原生 Webpack 对所有资源文件做的所有解析、转译、合并操作本质上都是在同一个线程内串行执行,CPU 利用率极低,因此,理所当然地,社区出现了一些以多进程方式运行 Webpack࿰…...
Vue的介绍与使用
1.Vue的介绍 内容讲解 【1】Vue介绍 1.vue属于一个前端框架,底层使用原生js编写的。主要用来进行前端和后台服务器之间的一个交互。 2.Vue是一套构建用户界面的渐进式前端框架。 “渐进式框架”简单的来说你可以将Vue作为你的应用一部分嵌入其中,代理…...
MYSQL双主双从,使用Keepalived双机热备+LVS高可用群集
MYSQL双主双从,使用Keepalived双机热备LVS高可用群集 文档只记录KeepalivedLVSmysql主从,不包含检验,如需检验,请自行添加web服务器 一、IP规划 服务器IP备注master1192.168.100.131master2的从master2192.168.100.132maste…...
9.计算机视觉—目标检测
目录 1.物体检测边缘框目标检测数据集总结边缘框代码实现2.锚框:目标检测的一种方法IoU—交并比赋予锚框标号使用非极大值抑制(NMS)输出总结代码实现1.物体检测 边缘框 一个边缘框可以通过四个数字定义 (左上x,左上y),(右下x,右下y)(左上x,左上y,宽,高)(中间x,中间y…...
构造函数深入理解
目录 构造函数构造函数体赋值初始化列表初始化列表格式初始化列表的意义以及注意点const修饰的成员变量初始化对象成员具体初始化的地方缺省值存在的意义例子1例子2 初始化与赋值引用成员变量的初始化注意点1注意点2我的疑惑 自定义类型成员初始化例子1例子2例子3例子4 初始化列…...
Rocky Linux 9 快速安装docker 教程
前述 CentOS 7系统将于2024年06月30日停止维护服务。CentOS官方不再提供CentOS 及后续版本,不再支持新的软件和补丁更新。CentOS用户现有业务随时面临宕机和安全风险,并无法确保及时恢复。由于 CentOS Stream 相对不稳定,刚好在寻找平替系统…...
go语言并发编程1-Gouroutine
参考文档:www.topgoer.com 使用方法 直接包装成函数,go关键字触发即可 注意事项 1 main方法结束后,main方法内启动的子协程会立即结束,无论是否执行完毕; 启动多个groutine 使用sync包的WaitGroup来控制…...
Sylar服务器框架——Http模块
1、http.h 定义了HttpMethod和HttpStatus /* Request Methods */ #define HTTP_METHOD_MAP(XX) \XX(0, DELETE, DELETE) \XX(1, GET, GET) \XX(2, HEAD, HEAD) \XX(3, POST, POST) \XX(4, PUT, …...
7km远距离WiFi实时图传模块,无人机海上无线传输方案,飞睿智能WiFi MESH自组网技术
在浩瀚无垠的海洋上,无人机正在开启一场前所未有的技术创新。它们不再只是天空的舞者,更是海洋的守望者,为我们带来前所未有的视野和数据。而这一切的背后,都离不开一项创新性的技术——飞睿智能远距离WiFi实时图传模块与无线Mesh…...
2024年上半年网络工程师下午真题及答案解析
试题一(20分) 某高校网络拓扑如下图所示,两校区核心(CORE-1、CORE-2),出口防火墙(NGFW-1、NGFW-2)通过校区间光缆互联,配置OSPF实现全校路由收敛,两校区相距40km。两校区默认由本地…...
Jmeter下载、安装及配置
1 Jmeter介绍 Jmeter是进行负载测试的工具,可以在任何支持Java虚拟机环境的平台上运行,比如Windows、Linux、Mac。 Jmeter模拟一组用户向目标服务器发送请求,并统计目标服务器的性能信息,比如CPU、memory usage。 2 Jmeter下载 …...
掌握高效实用的VS调试技巧
🔥 个人主页:大耳朵土土垚 1.编程常见的错误 1.1编译型错误 编程编译型错误是指在编译代码时发现的错误。编译器在编译过程中会检查代码是否符合语法规范和语义要求,如果发现错误会产生编译错误。 直接看错误提示信息(双击&#…...
实验2 字符及字符串输入输出与分支程序设计实验
字符及字符串输入输出 从键盘输入两个一位十进制数,计算这两个数之和,并将结果在屏幕上显示出来。 分支程序设计 从键盘输入一字符,判断该字符是小写字母、大写字母、数字或者其他字符。若输入为小写字母,显示“You Input a Lo…...
docker容器间网络仿真工具-pumba
docker-tc&pumba docker-tc:docker-tc项目仓库 pumba:pumba项目仓库 这两个项目理论上都可以实现对容器间的网络环境进行各种模拟干预,包括延迟,丢包,带宽限制等。 但是我在实际使用时,发现docker-tc这个工具在进行网络进行模…...
A36 STM32_HAL库函数 之PCD通用驱动 -- B -- 所有函数的介绍及使用
A36 STM32_HAL库函数 之PCD通用驱动 -- B -- 所有函数的介绍及使用 1 该驱动函数预览1.11 HAL_PCD_SOFCallback1.12 HAL_PCD_ResetCallback1.13 HAL_PCD_SuspendCallback1.14 HAL_PCD_ResumeCallback1.15 HAL_PCD_ISOOUTIncompleteCallback1.16 HAL_PCD_ISOINIncompleteCallbac…...
vue2 + element三级菜单实现模板
需求: 需要一个含有三级菜单的结构模板,用于业务快速开发。 解决: sidebar.vue <template><el-menu :default-active"defaultActive" class"el-menu-vertical-demo" active-text-color"#ffd04b"&…...
vue H5页面video 视频流自动播放, 解决ios不能自动播放问题
视频组件 <videostyle"width: 100%; height: 100%;object-fit: fill"class"player"refplayer_big_boxcontrolspreloadautoplay //自动播放muted //是否静音playsinline"true"x5-playsinline""webkit-playsinline"tru…...
自闭症儿童:探索症状背后的多彩内心世界
在星启帆自闭症康复中心,我们每天与一群独特而珍贵的孩子相遇——他们,是自闭症谱系障碍的患儿。自闭症,这一复杂的神经发育障碍,以其多样化的症状表现,为每个孩子的生活轨迹绘上了不同的色彩。 自闭症孩子的症状各异…...
在Centos7上安装PostgreSQL16的详细步骤
文章目录 环境一、准备二、postgresql下载方法一:wget下载方法二:下载压缩包解压 三、创建用户组、用户四、创建数据主目录五、配置环境变量六、initdb初使化数据库七、配置服务八、设置开机自启动九、设置防火墙十、启动数据库服务 环境 CPU: 4 核心或以…...
MySQL 图形化界面
填完信息之后,圆圈处可以验证是否可以连接数据库 展示所有数据库(因为有的可能连上,却没有数据库显示)...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
第八部分:阶段项目 6:构建 React 前端应用
现在,是时候将你学到的 React 基础知识付诸实践,构建一个简单的前端应用来模拟与后端 API 的交互了。在这个阶段,你可以先使用模拟数据,或者如果你的后端 API(阶段项目 5)已经搭建好,可以直接连…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
【Ftrace 专栏】Ftrace 参考博文
ftrace、perf、bcc、bpftrace、ply、simple_perf的使用Ftrace 基本用法Linux 利用 ftrace 分析内核调用如何利用ftrace精确跟踪特定进程调度信息使用 ftrace 进行追踪延迟Linux-培训笔记-ftracehttps://www.kernel.org/doc/html/v4.18/trace/events.htmlhttps://blog.csdn.net/…...
