当前位置: 首页 > news >正文

Webpack 5 核心机制详解与打包性能优化实践

在这里插入图片描述

🤖 作者简介:水煮白菜王,一个web开发工程师 👻
👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持💕💕💕

目录

    • Webpack 5 相较于 Webpack 4 的主要改进
    • 安装
    • 生命周期
      • Compiler Hooks
      • use hooks
    • webpack中的loader(转换器)
      • 工作原理
      • 常用loader
      • 自定义loader
    • webpack中的plugins(插件)
      • 工作原理
      • 自定义plugins
    • 打包过程
      • 加速webpack打包速度和减小打包体积的优化
      • webpack配置
      • webpack配置拆分
        • webpack.config.common.js文件公共环境配置
        • webpack.config.dev.js文件开发环境配置 npx webpack -c ./webpack.config.dev.js
        • webpack.config.prod.js文件生产环境配置 npx webpack -c ./webpack.config.prod.js
        • webpack.config.js 运行:webpack -c ./webpack.config.js --env development
      • 封装webpack自定义插件
    • 如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀

Webpack 5 相较于 Webpack 4 的主要改进

  1. 性能改进:webpack5在构建速度和打包体积方面进行了一些优化。它引入了持久缓存,可以减少构建时间。
    此外,webpack5还引入了更好的树摇(tree shaking)算法,可以更好地优化打包体积。
  2. 模块联邦(Module Federation)新增特性:这是webpack5中最重要的新功能之一。模块联邦允许不同的应用程序共享模块,从而实现更好的代码复用和拆分。这对于构建大型的微服务架构非常有用。
new ModuleFederationPlugin({name: 'myApp',filename: 'remoteEntry.js',remotes: {},exposes: {'./Button': './src/Button',},shared: { react: { singleton: true } },
});
  1. 支持WebAssembly:webpack5对WebAssembly提供了更好的支持。它可以直接导入和导出WebAssembly模块,并且可以通过配置进行优化。
  2. 缓存策略增强:webpack5引入了更好的缓存策略,可以更好地利用浏览器缓存。这可以减少用户在更新应用程序时需要下载的文件数量。
  3. Tree Shaking 改进:webpack5引入了更好的Tree Shaking算法,可以更好地识别和删除未使用的代码。这可以进一步减少打包体积。
  4. 改进的持久缓存:webpack5引入了更好的持久缓存策略,可以更好地利用缓存。这可以减少构建时间。
特性Webpack 5 改进
性能改进Webpack 5 在构建速度和打包体积方面进行了优化。引入了持久缓存机制,显著减少重复构建时间。
模块联邦(Module Federation)引入模块联邦功能,允许不同应用之间共享模块,提升代码复用能力,适用于微服务架构和微前端项目。
WebAssembly 支持增强原生支持 WebAssembly 模块的导入与导出,无需额外 loader,支持异步加载、Tree Shaking 和 Code Splitting。
缓存策略增强引入更智能的浏览器缓存策略(如 deterministic ID 算法),提升长期缓存利用率,减少用户更新时的资源下载量。
Tree Shaking 改进使用更高级的 Tree Shaking 算法,支持导出级(export-level)和嵌套级的未使用代码识别与删除,进一步减小打包体积。
持久缓存改进引入基于文件系统的持久化缓存(cache: { type: 'filesystem' }),大幅提升开发阶段的增量构建速度。

其中最显著的变化是 webpack5 引入了持久化缓存机制,使得构建速度大幅提升。此外,webpack5 改进了长期缓存策略,支持更好的 Tree Shaking 和代码分割功能

安装

npm init -y     // 初始化package.json
npm install webpack webpack-cli --save-devnpx webpack --watch     // 监听文件修改
npx webpack-dev-server  // 以server的方式启动项目,不会打包物理文件,而是输出到内存

生命周期

Compiler Hooks

beforeRun:在webpack开始运行之前调用,执行全局初始化逻辑,例如异步加载配置、插件依赖项等。

run:在webpack开始运行时调用,可以在此做一些全局处理 ,一些初始化操作。

beforeCompile:在webpack开始编译之前调用,修改编译参数、注入额外上下文。

compile:在webpack开始编译时调用,初始化与本次编译相关的状态。

make:在webpack开始构建编译器时调用,启动模块解析、构建等操作,可在此阶段添加自定义入口点或资源。

afterCompile:在webpack完成编译之后调用,获取完整的模块依赖图,进行最终分析或优化。

emit:在webpack生成最终的资源之前调用,添加、修改或删除最终输出的资源(如生成额外文件)。

afterEmit:在webpack生成最终的资源之后调用,做一些清理工作或触发后续流程。

done:在webpack完成构建之后调用,清理临时资源、输出构建信息、发送通知。

Hook 名称触发时机使用场景
beforeRun在 Compiler 开始运行前触发(如执行 webpack()可用于初始化插件或设置运行时配置
run在 Compiler 开始运行时触发(异步)类似入口点,可以在此做一些全局处理 ,一些初始化操作
beforeCompile在编译开始前触发准备编译所需的数据或资源
compile在编译开始时触发初始化编译过程,执行一些初始化操作,例如创建 Compilation 实例
thisCompilation在 Compilation 创建之前触发用于监听后续的 Compilation 生命周期
compilation在 Compilation 被创建后触发插件可在此接入 Compilation 生命周期
make在模块解析开始时触发可以添加/修改模块依赖关系
afterCompile在编译完成后触发对编译结果做最后调整或校验
emit在生成最终输出资源之前触发可以修改输出内容,如添加额外文件
afterEmit在输出资源之后触发清理 emit 阶段使用的临时数据
done整个构建流程完成之后触发执行清理工作或输出构建耗时信息
failed构建失败时触发处理异常、记录错误日志

use hooks

module.exports = {// ...plugins: [{apply: (compiler) => {compiler.hooks.beforeRun.tap('MyPlugin', () => {console.log('Before run');});compiler.hooks.done.tap('MyPlugin', () => {console.log('Build done');});}}]
};//在这个示例中,我们定义了一个自定义插件,并利用beforeRun和done两个生命周期钩子函数。在这些钩子函数中,我们可以实现自定义行为,如输出日志信息。

webpack中的loader(转换器)

工作原理

webpack loader 在 webpack 构建过程中的生命周期中的工作主要分为以下几个阶段:

  • 解析阶段:webpack 会根据配置文件中的入口文件,递归解析所有的依赖模块。在这个阶段,webpack 会根据文件的后缀名来确定使用哪个 loader 来处理该文件。

  • 编译阶段:在这个阶段,webpack 会将解析后的模块转换成 AST(抽象语法树),并且根据配置文件中的规则,将模块中的代码进行转换和处理。
    这个阶段是 loader 的主要工作阶段,loader 可以对模块进行各种处理,例如转换代码、添加额外的功能等。

  • 生成阶段:在这个阶段,webpack 会根据处理后的模块生成最终的输出文件。输出文件的格式和路径可以通过配置文件进行配置。

在这些阶段中,loader 主要在编译阶段发挥作用。loader 可以通过导出一个函数来定义自己的处理逻辑,这个函数接收一个参数,即待处理的模块的源代码,然后返回处理后的代码。

开始编译阶段
获取模块源代码
创建抽象语法树AST
是否有匹配的loader?
调用loader处理函数
直接使用原始代码
loader处理转换
返回处理后的代码
更新AST
分析模块依赖
递归处理依赖模块
生成最终代码
结束编译阶段

常用loader

以下是一些常用的webpack loader:

Loader描述
babel-loader用于将ES6+的JavaScript代码转换为ES5代码,以便在旧版本浏览器中运行。
css-loader用于解析CSS文件,并处理其中的import和url()等语法。
style-loader将解析后的CSS代码以<style>标签的形式插入到HTML文件中。
file-loader用于处理文件资源(如图片、字体等),并将其复制到输出目录中。
url-loader类似于file-loader,但可以根据文件大小将文件转换为DataURL,以减少HTTP请求。
sass-loader用于将Sass/SCSS代码转换为CSS代码。
less-loader用于将Less代码转换为CSS代码。
postcss-loader用于对CSS代码进行后处理,如自动添加浏览器前缀等。
vue-loader用于解析和转换Vue单文件组件。
ts-loader用于将TypeScript代码转换为JavaScript代码。

自定义loader

// 核心代码:function clearConsoleLoader(source) {// 使用正则表达式匹配并替换console语句const modifiedSource = source.replace(/console\.[a-z]+\(.+\);?/g, '');return modifiedSource;
}module.exports = clearConsoleLoader;//使用
module.exports = {// ...module: {rules: [{test: /\.js$/,exclude: /node_modules/,use: ['babel-loader','./path/to/clearConsoleLoader.js']}]}
};

webpack中的plugins(插件)

工作原理

webpack 插件是用来扩展 webpack 功能的工具,它可以在 webpack 构建过程中的不同阶段执行一些额外的操作。

插件的工作原理是通过在 webpack 的构建过程中的不同生命周期中注册一些钩子函数,然后在对应的阶段执行这些钩子函数中的逻辑。

webpack 的构建过程中有以下几个生命周期:

  • 初始化阶段:在这个阶段,webpack 会初始化配置参数,加载插件,并准备开始编译。

  • 编译阶段:在这个阶段,webpack 会从入口文件开始递归解析所有的依赖模块,并将模块转换成 AST(抽象语法树),然后根据配置文件中的规则进行转换和处理。

  • 完成编译阶段:在这个阶段,webpack 已经完成了所有的模块的转换和处理,并且生成了最终的输出文件。

  • 输出阶段:在这个阶段,webpack 会将生成的输出文件写入到磁盘上。

插件可以在这些生命周期中的任意阶段注册对应的钩子函数,并在钩子函数中执行一些额外的操作。

插件钩子注册点
初始化钩子
初始化阶段
编译钩子
编译阶段
完成编译钩子
完成编译阶段
输出钩子
输出阶段

自定义plugins

class MyPlugin {apply(compiler) {// 注册初始化阶段的钩子函数compiler.hooks.initialize.tap('MyPlugin', () => {console.log('MyPlugin initialized');});// 注册编译阶段的钩子函数compiler.hooks.compile.tap('MyPlugin', () => {console.log('MyPlugin compiling');});}
}module.exports = MyPlugin;// 使用const MyPlugin = require('./my-plugin');module.exports = {// ...plugins: [new MyPlugin(),],
};

打包过程

读取配置文件
解析模块依赖
加载器处理
插件处理
编译打包
输出打包文件
  • 读取配置文件:Webpack会首先读取配置文件,根据配置文件中的入口、出口等信息进行打包。

  • 解析模块依赖:Webpack会从指定的入口文件开始递归解析所有的模块依赖,直到找到所有的模块。

  • 加载器处理:对于不同类型的模块,Webpack会使用相应的加载器对其进行处理。例如,对于JavaScript模块,Webpack会使用Babel加载器将ES6语法转换为ES5语法;对于CSS模块,Webpack会使用CSS加载器将CSS代码打包进JS文件中。

  • 插件处理:在模块加载完成之后,Webpack会执行一系列插件,用于完成一些额外的任务,例如生成HTML文件、提取CSS文件等。

  • 编译打包:Webpack将经过处理的模块和插件生成最终的打包文件。通常情况下,Webpack会生成一个或多个JavaScript文件,同时也可以生成其他类型的文件,例如CSS、图片等。

  • 输出打包文件:Webpack将生成的打包文件输出到指定的目录中。通常情况下,Webpack会将打包文件输出到dist目录下。

加速webpack打包速度和减小打包体积的优化

以下是一些加速Webpack打包和减小打包体积的技巧:

  1. 优化Webpack配置:使用Tree shaking来减小打包体积,设置Webpack的mode为production以启用UglifyJsPlugin等插件进行代码压缩和优化。

  2. 使用Webpack的code splitting功能:将代码分割成较小的块,以便在需要时动态加载。

  3. 压缩图片和字体文件:使用ImageMinWebpackPlugin和FontminWebpackPlugin等插件来压缩图片和字体文件,减小打包体积。

  4. 缓存:启用Webpack的缓存功能,以便在修改代码时只重新打包修改的文件,而不是重新打包所有文件。

  5. 使用DLLPlugin和DllReferencePlugin:将一些第三方库打包成单独的文件,以便在每次打包应用程序时不必重新打包这些库。

  6. 使用HappyPack插件:使用多线程来加速Webpack打包,以便同时处理多个任务。

  7. 使用externals选项:将一些不需要打包的库从打包中排除,以便减小打包体积。

  8. 使用Webpack-bundle-analyzer插件:分析打包后的文件,以便找出冗余的代码和依赖关系,进行优化。

这些技巧可以帮助优化Webpack的打包速度和打包体积。

优化方法具体实现
优化Webpack配置使用Tree shaking,设置mode: 'production'启用UglifyJsPlugin等优化插件
使用code splitting动态加载分割后的代码块(如import()SplitChunksPlugin
压缩图片和字体文件通过ImageMinWebpackPluginFontminWebpackPlugin插件压缩资源文件
启用缓存配置cache: true或使用HardSourceWebpackPlugin加速重复构建
使用DLLPlugin预编译第三方库为独立文件(DLL),通过DllReferencePlugin引用
多线程打包(HappyPack)使用HappyPackthread-loader并行处理任务
排除外部库(externals)配置externals将库(如jQuery)排除,通过CDN引入
分析打包体积使用webpack-bundle-analyzer可视化分析依赖,优化冗余代码

webpack配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 自动引入资源插件  npm install --save-dev html-webpack-plugin
const MiniCssExtracPlugin = require("mini-css-extrac-plugin"); // css抽离
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  //css压缩 npm install css-minimizer-webpack-plugin  --save-dev 
const TerserPlugin = require("terser-webpack-plugin"); // js压缩  npm install --save-dev terser-webpack-plugin
//加载toml、yarm、json5数据资源 npm install toml yarm json5 -D
const toml = require("toml");
const yarm = require("yarm");
const json5 = require("json5");module.exports = (env) => {return {// 手动分离公共文件,通过配置成对象的方式实现多入口代码分割// entry: {//  index:{//    import:"./src/index.js",//    dependOn: "shared"  // 抽离公共文件//  },//  shared: "lodash"      // 公共的js文件// },// 多入口// entry: {// 	 pageOne: './src/pageOne/index.js',//  	pageTwo: './src/pageTwo/index.js',//  	pageThree: './src/pageThree/index.js',// },// 单入口entry: {index: "./src/index.js",},output: {filename: "scripts/[name].[contenthash].js", // 将所有的js放入同一个文件夹,并且根据文件名自动命名path: path.resolve(__dirname, "./dist"),clean: true, // 清除上一次的垃圾文件assetModuleFilename: "images/[contenthash][ext]", // 在images目录下,根据文件内容自动生成hash文件名publicPath: "https://*****.com/", // 公共路径(cdn域名或者本地localhost)},mode: env.prodection ? "prodection" : "development", // 生产环境或者开发环境 package.json 启动命令:npx webpack --env prodectiondevtool: "cheap-module-source-map",     // 真实报错文件指向,生产环境一般不开启sourcemap// 插件(非必要的,缺少也不影响项目打包)plugins: [new HtmlWebpackPlugin({template: "./index.html", // 模板filename: "app.html",inject: "body", // script 存在的位置hash: true, // 解决缓存minify: {removeAttributeQuotes: true, // 压缩,去掉引号},}),new MiniCssExtracPlugin({filename: "style/[contenthash].css",}),],devServer: {static: "./dist", // 监听根目录文件变化,自动刷新页面插件 npm install --save-dev webpack-dev-server//反向代理proxy: {"/ajax": {target: "https:**********",ws: true,changeOrigin: true,},},},// 模块(必要的,缺少影响项目打包)module: {rules: [//资源模块类型我们称之为Asset Modules Type,总共有四种,来代替loader,分别是:// asset/resource:发送一个单独的文件并导出URL,替代file-loader// asset/inline:导出一个资源的data URI(base64),替代url-loader// asset/source:导出资源的源代码,之前通过使用raw-loader实现// asset:介于asset/resource和asset/inline之间, 之前通过url-loader+limit属性实现。{test: /\.(png|gif|jp?g|svg|webp|ico)$/, // 正则图片文件type: "asset",generator: {filename: "images/[contenthash][ext]", // 优先级高于 assetModuleFilename},},{// 支持less// npm install style-loader css-loader less-loader less --save-dev// 抽离 npm install mini-css-extrac-plugin  --save-dev   webpack5环境下构建的插件test: /\.(le|c)ss$/, // .less and .cssuse: [MiniCssExtracPlugin.loader,/* "style-loader", */ "css-loader","less-loader"],},{test: /\.(woff|woff2|eot|ttf|oft)$/, // 正则字体文件type: "asset/resource",},//加载csv、xml数据资源 npm install csv-loader xml-loader -D{test: /\.(csv|tsv)$/,use: "csv-loader",},{test: /\.xml$/,use: "xml-loader",},//加载toml、yarm、json5数据资源{test: /\.toml$/,type: "json",parser: {parse: toml.parse,},},{test: /\.yarm$/,type: "json",parser: {parse: yarm.parse,},},{test: /\.json5$/,type: "json",parser: {parse: json5.parse,},},// loader工具 支持数组方式链式调用,数组靠后的元素先执行{// 压缩图片//图片小于一定大小使用base64 否则使用file-loader产生真实图片 npm install url-loader --save-devtest: /\.(png|gif|jp?g|svg|webp|ico)$/, // 正则use: [{loader: "url-loader",options: {limit: 5000, //小于限定使用base64name: "home/images/[name].[hash:8].[ext]",publicPath: `../../`,esModule: false,},},],},// 使用babel-loader npm install -D babel-loader @babel/core @babel/preset-env// regeneratorRuntime是webpack打包生成的全局辅助函数,由babel生成,用于兼容 async/await 的语法// npm install --save @babel/runtime// npm install --save-dev @babel/plugin-transform-runtime{test: /\.js$/,exclude: /node_modules/, // *业务代码里面可能会引入node_modules外部js,这些js不需要babel-loader编译,因此需要排除掉use: {loader: "babel-loader", // *引入babel-loaderoptions: {presets: ["@babel/preset-env"], // *引入预设plugins: [["@babel/plugin-transform-runtime", // *配置插件信息],],},},},],},optimization: {minimizer: [new CssMinimizerPlugin(),new TerserPlugin()],   //代码压缩 mode改为 productionsplitChunks: {// 缓存cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: "vendors",chunks: "all", // 自动重复代码抽离},},},},};
};

webpack配置拆分

webpack.config.common.js文件公共环境配置

const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 自动引入资源插件  npm install --save-dev html-webpack-plugin
const MiniCssExtracPlugin = require("mini-css-extrac-plugin"); // css抽离
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); //css压缩 npm install css-minimizer-webpack-plugin  --save-dev
const TerserPlugin = require("terser-webpack-plugin"); // js压缩  npm install --save-dev terser-webpack-plugin
//加载toml、yarm、json5数据资源 npm install toml yarm json5 -D
const toml = require("toml");
const yarm = require("yarm");
const json5 = require("json5");module.exports = {entry: {index: "./src/index.js",},output: {path: path.resolve(__dirname, "./dist"),clean: true, // 清除上一次的垃圾文件assetModuleFilename: "images/[contenthash][ext]", // 在images目录下,根据文件内容自动生成hash文件名},// 插件(非必要的,缺少也不影响项目打包)plugins: [new HtmlWebpackPlugin({template: "./index.html", // 模板filename: "app.html",inject: "body", // script 存在的位置hash: true, // 解决缓存minify: {removeAttributeQuotes: true, // 压缩,去掉引号},}),new MiniCssExtracPlugin({filename: "style/[contenthash].css",}),],// 模块(必要的,缺少影响项目打包)module: {},optimization: {splitChunks: {// 缓存cacheGroups: {vendor: {test: /[\\/]node_modules[\\/]/,name: "vendors",chunks: "all", // 自动重复代码抽离},},},},
};
webpack.config.dev.js文件开发环境配置 npx webpack -c ./webpack.config.dev.js
module.exports = {output: {filename: "scripts/[name].js", // 将所有的js放入同一个文件夹,并且根据文件名自动命名},mode: "development", // 生产环境或者开发环境 package.json 启动命令:npx webpack --env prodectiondevtool: "cheap-module-source-map", // 真实报错文件指向,生产devServer: {static: "./dist", // 监听根目录文件变化,自动刷新页面插件 npm install --save-dev webpack-dev-server//反向代理proxy: {"/ajax": {target: "https:**********",ws: true,changeOrigin: true,},},},
};
webpack.config.prod.js文件生产环境配置 npx webpack -c ./webpack.config.prod.js
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  //css压缩 npm install css-minimizer-webpack-plugin  --save-dev 
const TerserPlugin = require("terser-webpack-plugin"); // js压缩  npm install --save-dev terser-webpack-pluginmodule.exports = {output: {filename: "scripts/[name].[contenthash].js", // 将所有的js放入同一个文件夹,并且根据文件名自动命名publicPath: "https://*****.com/", // 公共路径(cdn域名或者本地localhost)},mode: "prodection", // 生产环境或者开发环境 package.json 启动命令:npx webpack --env prodectionoptimization: {minimizer: [new CssMinimizerPlugin(), new TerserPlugin()], //代码压缩 mode改为 production},performance: {hints: false, // 关闭性能提示},
};
webpack.config.js 运行:webpack -c ./webpack.config.js --env development
const { merge } = require ('webpack-merge')   // npm install webpack-merge -D
const commonConfig = require ('./webpack.config.common')
const productionConfig = require ('./webpack.config.prod')
const developmentConfig = require ('./webpack.config.dev')module.exports = (env) => {switch (true) {case env.development :return merge(commonConfig,developmentConfig)case env.production :return merge(commonConfig,productionConfig)defult:return new Error()}
}

封装webpack自定义插件

  1. 创建一个 JavaScript 文件,并导出一个函数。这个函数将作为你的插件的构造函数。

  2. 在函数中定义一个 apply 方法,该方法接收一个 compiler 参数。这个 compiler 对象是 Webpack 的核心,它包含了 Webpack 的所有配置和工作流程。

function MyPlugin() {} // 构造函数// 核心 apply 方法
MyPlugin.prototype.apply = function(compiler) {// 插件逻辑实现
};
  1. 在 apply 方法中,可以通过 compiler.hooks 对象访问 Webpack 的生命周期钩子。通过这些钩子,你可以在 Webpack 运行的不同阶段执行自定义代码。
compiler.hooks.done.tap('PluginName', (stats) => {console.log('编译完成!');
});
  1. 实现你的插件逻辑,例如在特定的 Webpack 钩子上注册回调函数,向编译器添加自定义插件等。

  2. 将你的插件打包成一个 npm 模块,并在项目中引入和使用它。

Webpack 插件本质上是一个具有 apply 方法的类或函数对象。通过挂接到 Webpack 编译器的生命周期钩子,我们可以实现各种构建时的定制化功能,如资源处理、日志输出、文件生成等。


const MyPlugin = function() {};MyPlugin.prototype.apply = function(compiler) {compiler.hooks.done.tap('MyPlugin', (stats) => {console.log('Webpack 构建已完成!');if (stats.hasErrors()) {console.error('构建过程中出现错误');}});
};
module.exports = MyPlugin;上面示例我们定义了一个 MyPlugin 插件,它在 Webpack 编译完成后输出一条信息。
在 apply 方法中,我们使用 compiler.hooks.done 钩子注册了一个回调函数,在编译完成后输出一条消息。要使用这个插件,你需要将它打包成一个 npm 模块,并在 Webpack 配置文件中引入和使用它:const MyPlugin = require('my-plugin');module.exports = {// ...plugins: [new MyPlugin()]
};

在这个示例中,我们在 Webpack 配置文件中引入了 MyPlugin 插件,并通过 plugins 选项将其添加到插件数组中。这样一来,当 Webpack 进行编译时,MyPlugin 就会被自动启用并执行相应的逻辑。

如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀

在这里插入图片描述

http://www.dtcms.com/a/265485.html

相关文章:

  • 牛客:HJ16 购物单【01背包】【华为机考】
  • 前端单元测试覆盖率工具有哪些,分别有什么优缺点
  • 在 Sepolia 上使用 Zama fhEVM 构建隐私代币与流动性池:全流程实战指南
  • Android音视频探索之旅 | CMake基础语法 创建支持Ffmpeg的Android项目
  • 【免费.NET方案】CSV到PDF与DataTable的快速转换
  • 音频动态压缩算法曲线实现
  • C++【成员变量、成员函数、this指针】
  • OSPF高级特性之FRR
  • Vue 项目在哪里加载「字典数据」最好
  • 基于 alpine 构建 .net 的基础镜像
  • 开源模型应用落地-让AI更懂你的每一次交互-Mem0集成Qdrant、Neo4j与Streamlit的创新实践(四)
  • Zookeeper 客户端 .net访问框架 ZookeeperNetEx项目开发编译
  • 开源 C# .net mvc 开发(六)特殊控制控制台、周期、邮件编程
  • 深度实战:Ubuntu服务器宕机排查全记录
  • 月付物理服务器租用平台-青蛙云
  • 基于 govaluate 的监控系统中,如何设计灵活可扩展的自定义表达式函数体系
  • npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree
  • Python Set() 完全指南:从入门到精通
  • R语言开发记录,一
  • 前端-HTML-day1
  • Rust Web 全栈开发(二):构建 HTTP Server
  • 主流分布式中间件及其选型
  • locate命令的原理是啥
  • OpenCV CUDA模块设备层-----在GPU 上高效地执行两个 uint 类型值的最大值比较函数vmax2()
  • Frida:配置自动补全 in VSCode
  • 搭建VirtualBox-6+vagrant_2+docker+mysql5.7的步骤
  • 客户案例 | 某新能源车企依托Atlassian工具链+龙智定制开发服务,打造符合ASPICE标准的研发管理体系
  • 云原生系统DOCKER中容器系统搭建
  • Python字符与ASCII转换方法
  • Ubuntu Gnome 安装和卸载 WhiteSur-gtk-theme 类 Mac 主题的正确方法