前端工程化之新晋打包工具
新晋打包工具
- 新晋打包工具
- 前端模块工具的发展历程
- 分类
- 初版构建工具
- grunt
- 使用场景
- gulp
- 采用管道机制
- 任务化配置与api简洁
- 现代打包构建工具基石--webpack
- 基于webpack改进的构建工具
- rollup 推荐
- 举例说明
- package.json
- rollup.config.mjs
- my-extract-css-rollup-plugin.mjs
- src/index.js
- src/utils.js
- src/index.css
- src/utils.css
- build/cjs.js
- build/esm.js
- build/umd.js
- build/index.css
- build/666.css
- 使用场景
- 不适用场景
- Parcel 不推荐
- 举例说明
- parcel/index.html
- parcel/index.js
- parcel/App.js
- parcel/index.css
- package.json
- 使用场景
- 突破JS语言特性的构建工具
- SWC 推荐使用 √ - 平替babel
- jsc-parser语法解析相关配置
- jsc-target 输出代码的es版本
- 典型配置案例
- ESbuild - 作为工具去使用的
- 基于ES Module的bundleless(no bundle)构建工具 => vite
- 基于bundle的解决方案
- vite - 重点掌握
- vite原理
- 为什么vite之前没有,到2021年后才有这样的开发链路呢?
- vite插件
- package.json
- vite.config.js
- 自定义插件 -plugins/myPlugin.js
- vite插件的相关钩子
- 通用钩子
- rspack - 推荐尝试使用
- 示例:通过 rsbuild 创建一个工程
- turpopack 国外的
新晋打包工具
构建为了将工程化的思想和自动化的思想应用在前端的工程链路中
前端模块工具的发展历程
- 09年,commonJS:指定浏览器外js的相关 api 规范, nodejs 就采用了这样的规范
- 11年,requireJS:作为客户端模块加载器,提供了异步加载模块的能力,之后就变成了 AMD 的规范
- 13年,grunt,gulp 诞生。
- 14年,UMD,统一模块定义,跨平台的前后端兼容
- 14年,6to5,ES6 语法 => ES5,经历了 词法分析,语法分析,AST => new AST => generator code。这也就是 babel 的能力
- 14年,system is 简化模块加载工具
- 14年,webpack,第一个稳定版本的
- 15年,ES6 规范正式发布的
- 15年,rollup 基于ES6模块化,并且提供 tree shaking相关能力
- 17年,Parcel,零配置,内部集成配置,能力进行收口,parcel,index.html
=> 做平台,开发基础能力,具备插件化机制 - 19年,构建工具深水区,不再使用js语言卷了,使用go,rust语言来卷。由于JS是高级语言,使用 babel 会经历各种AST转换
snowpack,使用rust语言,天生支持多线程能力 - 20年,浏览器对 ESM,http2 支持,使得 bundless 思路开始出现,esbuild 进入到大众视野中
- 21年,vite诞生
分类
- 初版构建工具
- 现代打包构建工具基石 webpack
- 突破JS语言特性的构建工具
- esmodule 的 bundless 构建工具
初版构建工具
grunt
最早的构建工具,构建工具的鼻祖
基于 nodejs 来开发的,借助nodejs实现跨系统,跨平台的操作文件系统
自动化的配置工具集,像官方所说的是一种 Task Runner,是基于任务的,整体配置json,由JSON配置设置驱动的。
基于 grunt 可以进行JS语法监测,或者合并一些JS文件,合并后的文件压缩,以及将我们预处理的sass,less文件进行编译
配置驱动、插件化、任务链
'use strict'
module.exports = function (grunt) {//构建的初始化配置grunt.initConfig({/*配置具体任务 */pkg: grunt.file.readIsON('package.json'),dirs: {src: 'path',dest: 'dest/<%= pkg.name >/<%= pkg.version 名>'},// clean任务(删除dest/test_grunt/0.0.1 目录下非min的文件)clean: {js: ['<%= dirs.dest &>/*.js', '!<%= dirs.dest %>/*.min.js'],css: ['<%= dirs,dest %>/*.css', '!<%= dirs.dest 名>/*.min.css'],},// copy任务(拷贝path目录下的文件到dest目录)copy: {main: {files: [// includes files within path{expand: true,src: ['path/*'],dest: '<%= dirs.dest %>/',filter: 'isFile',},],},},//concat任务(将dest目录下的a.js和b.js合并为built.js)concat: {options: {separator: '\n',},concatCss: {src: ['<%= dirs,dest &>/a.css', '<%= dirs.dest &>/path/b.css'],dest: '<%= dirs.dest %>/built.css',},concatJs: {src: ['<%= dirs,dest &>/a.js', '<%= dirs.dest &>/b.js'],dest: '<%= dirs.dest %>/built.is'}},// cssmin任务(压缩css)cssmin: {target: {files: [{expand: true,cwd: '<%= dirs.dest %>',src: ['*.css', '!*.min.css'],dest: '<%= dirs.dest %>',ext: '.min.css'}]},},// uglify任务(压缩js)uglify: {options: {mangle: {except: ['jQuery', 'Backbone'],},},my_target: {files: {'<%= dirs.dest %>/bulit.min.js': ['<%= dirs.dest %>/*.js']},},},})// 载入要使用的插件grunt.loadNpmTasks('grunt-contrib-clean')grunt.loadNpmTasks('grunt-contrib-copy')grunt.loadNpmTasks('grunt-contrib-concat')grunt.loadNpmTasks('grunt-contrib-cssmin')grunt.loadNpmTasks('grunt-contrib-uglify')//注册刚配置好的任务grunt.registerTask('cls', ['clean'])grunt.registerTask('cpy', ['copy'])grunt.registerTask('con', ['concat'])grunt.registerTask('cmpCSS', ['cssmin'])grunt.registerTask('cmpJS', ['uglify'])grunt.registerTask('default', ['copy', 'concat', 'cssmin', 'uglify', 'clean'])
}
缺点:
针对 文件处理模式
- grunt 任务,基于磁盘文件操作,先读取 => 再处理 => 后写入
效率是非常低下的
grunt.initConfig({uglify: {files:{'dest/output.min.js': ['src/input1.js','src/input2.js']}}
})
读取 less => 编译 css => 写入磁盘 => 读取 css => 压缩处理 => 写入磁盘
使用场景
- 传统项目维护 已经是使用grunt来处理
- 简单任务自动化 使用grunt也足够了
gulp
基于 nodejs 的流式前端构建工具。特点:代码驱动任务,高效流处理,基于task驱动
完成 测试,检查,合并,压缩 能力
采用管道机制
采用管道pipe机制
处理文件,所有操作在内存中处理,基于内存流的,避免频繁io操作
在管道 pipe 中 =>使用 less 插件=>转成 css =>使用 minicss 插件压缩css => 写入磁盘,由于是在内存中完成的,因此效率提升
任务化配置与api简洁
gulp.task('css',()=>gulp.src('./src/css/**').pipe(cssmin()).pipe(gulp.dest('./dist/css'))
)
插件生态庞大,包含文件压缩,语法编译等
基于流式的高效性和插件驱动的灵活性
var gulp = require('gulp')
var pug = require('gulp-pug')
var less = require('gulp-less')
var minifyCss = require('gulp-csso')gulp.task('html',function(){return gulp.src('client/templates/*.pug').pipe(pug()).pipe(gulp.dest('build/html'))
})
gulp.task('css',function(){return gulp.src('client/templates/*.less').pipe(less()).pipe(minifycss()).pipe(gulp.dest('build/css'))
})gulp.task('default', ['html''css'])
现代打包构建工具基石–webpack
上篇文章中已说到了,这里就不再赘述了。
特性:基于各种各样配置,包含loader对文件进行编译处理,webpack内容当中,所有内容皆为模块,需要转译成JS模块,需要使用不同的loader进行处理,另外,还有插件的能力,webpack基于事件流的,集成自 tapable 的,学会开发自定义插件,了解compiler,complation 各自的有哪些钩子,并且钩子能做哪些事情,落地一些插件才行
基于webpack改进的构建工具
rollup 推荐
vue2,vue3,react,babel等,源码层面上,都是使用 rollup 做构建工具的
专注于 js 模块打包的工具
特点:高效性,轻量性,一般都是在前端 Library 基础类库,工具函数等打包,打包出来的效果要优于webpack的,体积也要优于webpack。
对于基础类库/工具函数库需要被其他函数库引用,像引入 vue2,vue3,react。针对他们的诉求肯定是越小越好,没有用到的相关特性就不要打包进来了,所以 tree shaking 能力是必备的,能够对当前代码进行静态分析,esModule的导入导出,没有用到的功能(deadcode )就会精准剔除
-
高效 tree shaking 能力
-
减小包体积,避免冗余依赖,适用于按需加载的场景
-
支持输出 ESM commonjs AMD IIFE UMD模块格式,满足不同环境需求
配置时候也比较简单,只需要在配置文件中进行如下操作:rollup index.js -f cjs -o bundle.cjs.js #输出 CommonJS格式
-
轻量化代码输出
几乎不添加额外代码
打包仅包含一些必要的函数,辅助代码 -
强大的插件生态,vite线上发布使用rollup进行打包的,vite扩展了rollup插件生态,包含代码转换,依赖解析,压缩等场景
-
@rollup/plugin-babel
-
@rollup/plugin-terser 压缩代码
-
@rollup/plugin-commonjs,将commonjs => ESM
很多相关的插件
针对 rollup 有插件,没有loader,但是也能对 非 js 文件进行处理,有扩展的能力
- transform 对代码进行转换
- 语法转换
- 添加额外功能
- 等等
因此在开发插件的时候,需要重点关注 transform 方法
举例说明
pnpm init
package.json
- “rollup-plugin-cleaner”:“^1.0.0”, —— 清除当前目录下的dist文件的
- “rollup-plugin-cleanup”:“^3.2.1”, —— 清除代码注释,删除无效的console等等
- “rollup-plugin-postcss”:“^4.0.2” —— 针对css文件的插件
{"name": "about-builder","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1","build":"npx rollup -c rollup.config.mjs --watch"},"keywords": [],"author": "","license": "ISC","dependencies":{"parcel": "^2.13.0","react":"^18.3.1","react-dom":"^18.3.1","rollup":"^4.27.4","rollup-plugin-cleaner":"^1.0.0", "rollup-plugin-cleanup":"^3.2.1","rollup-plugin-postcss":"^4.0.2"}, "devDependencies":{"process":"^0.11.10"}
}
rollup.config.mjs
使用rollup的话,就需要提供这样的一个配置文件
import postcss from "rollup-plugin-postcss"
import cleanup from "rollup-plugin-cleanup"
import cleaner from "rollup-plugin-cleaner"
import myExtractCssRollupPlugin from "./my-extract-css-rollup-plugin.mjs"/** @type {import("rollup").RollupOptions} */
export default {input: 'src/index.js',output: [{file: 'build/esm.js',format: 'esm'},{file: 'build/cjs.js',format: 'cjs' //指定当前模块规范},{file: 'build/umd.js',name: 'Echo',format: 'umd'}],plugins: [cleaner({targets: ['dist',"build"], //需清理的目录silent: false, //显示操作日志watch: true, //监听模式exclude: ['README.md'], //保留特定文件}),// 代码清理cleanup({comments: false,sourcemap: false,targets: ['build/*']}),// 处理css,将css内容从js文件中提取出来postcss({extract: true,extract: 'index.css'}),// 自定义插件myExtractCssRollupPlugin({filename: '666.css'})]
}
my-extract-css-rollup-plugin.mjs
/** 为什么 rollup 没有 loader 呢?* 因为 rollup 的 plugin 有 transform 方法,也就相当于 loader 的功能了。* Rollup 打包过程中对模块的代码进行转换操作
*/const extractArr=[]export default function myExtractCssRollupPlugin(opts) {return {name: 'my-extract-css-rollup-plugin',transform(code, id) {//在这里对代码进行转换操作if (!id.endsWith('.css')) {return null}// 将后缀为css的文件内容收集起来extractArr.push(code)return {// 转换后的代码code: '',// 可选的源映射信息,如果需要生成源映射的话map: { mappings: '' }}},//此方法在Rollup生成最终的输出文件之前被调用generateBundle(options, bundle) {this.emitFile({fileName: opts.filename,type:"asset",source:extractArr.join('/* #echo# */\n')})}}
}
src/index.js
import { add } from './utils.js'
// rollup 默认开启 tree shaking
import './index.css'function main() {console.log(add(1, 3))
}export default main
src/utils.js
import './utils.css'function add(a, b) {return a + b;
}export { add };
src/index.css
body{background: skyblue;
}
src/utils.css
.bbb{background: red;
}
执行
pnpm run build
得到:
build/cjs.js
'use strict';function add(a, b) {return a + b;
}function main() {console.log(add(1, 3));
}module.exports = main;
build/esm.js
function add(a, b) {return a + b;
}function main() {console.log(add(1, 3));
}export { main as default };
build/umd.js
(function (global, factory) {typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :typeof define === 'function' && define.amd ? define(factory) :(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Echo = factory());
})(this, (function () { 'use strict';function add(a, b) {return a + b;}function main() {console.log(add(1, 3));}return main;}));
build/index.css
.bbb{background: red;
}
body{background: skyblue;
}
build/666.css
export default undefined;/* #echo# */
export default undefined;
使用场景
- 开发 js 库,工具函数
- 需要 tree shaking 优化的项目
- 生成环境打包 vite
不适用场景
- 依赖非 js 资源 非常多
Parcel 不推荐
- 完全零配置
- 构建速度快
parcel 官网
举例说明
还是在上面的 about-builder 包下,使用 React 框架来写案例
parcel/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><link rel="stylesheet" href="index.css">
</head>
<body><div id="app"></div><script type="module" src="./index.js"></script>
</body>
</html>
parcel/index.js
import { createRoot } from 'react-dom/client'
import App from './App.js'const container = document.getElementById('app')
const root = createRoot(container)
root.render(<App />)
parcel/App.js
export function App() {return <h1>Hello World!</h1>
}
parcel/index.css
body{background-color: skyblue;
}
package.json
去掉 main 那一行,也就是:"main": "index.js"
这个内容
执行:
npx parcel parcel/index.html
文件夹多了一个dist和.parcel-cache
页面:
热更新也是比较友好的
使用场景
适用小型项目
突破JS语言特性的构建工具
非 JS 语言相关的构建工具
SWC 推荐使用 √ - 平替babel
- speedy web Compiler 快速web编译器
=> Compiler + bundler (编译+构建 所组成的)
=> bundler 有一定的缺陷,推荐使用 Compiler 编译 能力
=> 强调 快速 的能力,使用rust 语言
实现的,使用多线程
-
简历中做一些优化,针对 webpack 做一些常规的优化,像进行分包,还有像通过引入cache提升构建速度,像leo-plugins等方式,只是针对webpack本身所作的优化,但是现在
webpack+babel
已经具备了性能瓶颈
=> 优化措施:webpack+swc
babel 对标 => swc
babel-loader => swc-loader -
文件比较多,使用 babel-loader 的话,需要经历 翻译、ast 是比较耗时的
使用swc的话,性能会得到质的飞跃 -
swc官方网站
-
性能表现原因:
- rust 语言编写,编译时确定运行的行为,不像js是解释执行,解释成机器语言再执行机器语言。rust 是多线程的这样的一个能力
-
功能覆盖
SWC 主要对 js 代码快速转换
,核心将es6+代码转换成 es5或者其他代码
,在这过程中会进行代码压缩优化
等相关的一些操作,比如swc能很好的处理箭头函数
,模板字符串
,解构赋值等es6+特性
的转换,还有针对ts语言
,tsx语言
等语言的处理,成熟度也是可以的 -
使用:简单转换代码
@swc/core @swc/clinpx swc source.js -o dist.js
const start = () => {console.log('app started') } // 转为 var start = function (){console.log('app started') }
jsc-parser语法解析相关配置
使用 swc-loader 时候,需要着重注意 JSC 相关配置
swc-loader
- JSC (javascript Compiler)
配置项:
options:{//jsc相关能力配置"jsc":{//当前需要转义哪些语言"parser":{//指定当前语言类型"syntax": "typescript", //ecmascript"tsx": true, //是否编译tsx"dynamicImport": true //是否支持动态导入}}
}
jsc-target 输出代码的es版本
配置对应的target
接着上面写:
options:{//jsc相关能力配置"jsc":{//当前需要转义哪些语言"parser":{//指定当前语言类型"syntax": "typescript", //ecmascript"tsx": true, //是否编译tsx"dynamicImport": true //是否支持动态导入}//配置对应target"target": "es2015" //输出代码的es版本"transform":{ //代码转换"react":{"runtime":"automatic"},//启动代码优化"optimizer":{"simplify": true //简化}}}
}
典型配置案例
.swcrc 配置文件
{"jsc": {"parser": {"syntax": "typescript","tsx": true,"decorators": true,},"transform":{ //代码转换"react":{"runtime":"automatic"}},"target": "es2018",//是否需要辅助函数"externalHelpers": true,"baseUrl": ".","paths": {"@/*": ["src/*"]}},"minify": true //进行代码压缩
}
也可以自己写一些插件
import{ readFilesync } from 'fs'
import { transform } from '@swc/core'const run = async () => {const code = readFileSync('./source.js','utf-8')const result= await transform(code,{filename:'source.js',})//·输出编译后代码console.log(result.code)
}
run()
ESbuild - 作为工具去使用的
vite 在开发环境下,使用 esbuild 预构建依赖
由于并发处理包的构建是非常快的,因此才会使用,而JS本质是解释型语言,执行代码的时候需要一边将源码翻译成机器语言,一边调度执行。
-
go编写程序,是编译型语言,少了动态解释过程
-
多线程
go语言具备多线程能力,将所有的包都进行深度开发,因为JS是单线程
,虽然也引入了webworker
做一些多线程的事情,但是还是有一些限制,比如说,go的多个线程之间是可以共享当前进程的内存空间
,但是JS的webworker是不能共享进程内存空间的
,如果想要数据共享
的话,需要通过postmessage
进行通信,但是这样的话,效率也比较低下的。因此,这也是JS的限制
=> 更高效的利用内存使用率 => 达到了更高的运行性能 -
全量定制
比如,webpack中会用到babel实现ES5的版本转义
,使用ESlint代码检查
,使用tsc完成typescript代码转义,检查
,使用less,scss
等,这些使用插件去实现的。
但是,esbuild中完全去重写,整套流程,工具都是重写的,意味着对这些文件的资源 tsx,jsx,js,ts等加载解析代码的生成逻辑,内部都会进行定制化开发,相对来说,成本也是非常高的,实现出来后,对编译的各个阶段都达到了非常好的性能。如果不去继续兼容webpack的loader,依然可能会达到不好的效果。
webpack尤其针对 babel 的代码编译,会频繁的经历 string => AST => AST => string =>AST => string 这样的阶段,因此,esbuild重写了大多数转译工具
,能够尽量共用相似的AST转换,减少AST结构的转换,进而提升内存利用率
-
ESbuild 特性
(1)极快的速度,无需缓存
(2)支持 ES6 commonjs 模块
(3)ES6 tree shaking
(4)API 可以同时用于 js 和 go
(5)兼容 ts,jsx语法
(6)支持plugins
这也是为什么 vite 使用 esbuild 作为包的转换
ESbuild官网
同时拷贝10个 three.js 库的扩展
基于ES Module的bundleless(no bundle)构建工具 => vite
http2 支持 多路复用 并发限制很大 10 50 100
浏览器 esm
基于bundle的解决方案
bundle based => entry 入口进行分析,分析当前的依赖内容,调用了哪些模块,对应的loader对当前进行处理 => modules,递归的完成这些模块的依赖分析 =>最终形成bundle => 启动 devServer 给到浏览器,然后浏览器去进行渲染
vite - 重点掌握
vite原理
而nobundle的思想:
本地启动一个服务,执行vite相关内容,会创建一个服务,启动devServer(本地请求资源服务),还有 websocket 两个服务(主要用于hm热更新)
no-bundle核心的两个特性:预构建、按需加载
使用按需加载的简单的vue3项目:
- 加载html,html中引入了main.js
还会引入 @vite/client,实现热更新
- 加载client资源(热更新)
监听消息
handleMessage方法:
在websocket中能看到payload.type,connect是建联,update是更新操作,等等。
先是建联:
更改 页面文字:
websocket会有update更新
类型是 js-update的话,会调用队列:
最终会发起 App.vue请求
App.vue请求会带着时间戳,不会复用之前的,避免了缓存的影响,就会拿到更改之后的数据替换之前的内容
-
加载main.js,引入了vue.js,style.css,等
-
加载vue.js,style.css等,比如,style.css使用css插件做处理,创建style标签用在header当中
为什么vite之前没有,到2021年后才有这样的开发链路呢?
- http2.x 支持,多路复用
之前webpack不拆包,将所有的都打包到一个bundle当中,热更新重新走整个链路的流程,最终形成bundle,然后再更新这个bundle,会受体积影响
现在都是使用websocket,支持单文件的热更新
多路复用
:
http1.0 会对单个域名有tcp请求的限制,限制 6-8 tcp请求链接的数量,因此,将多个文件合并到一个文件当中进行处理,避免限制对有些请求发送不出去
http2.x 有多路复用,同一个域名下对请求并发限制很大,10个,50个,100个同时请求服务器下的多个资源 - 浏览器支持 esm
webpack时候还不支持 esm 这样的一个特性,需要经历编译这一层
现在可以在浏览器中通过"import xxx"去加载到对应的资源内容
vite插件
使用 vite 创建 vue3 项目:
pnpm create vite my-vue3-app
使用vite构造的vue3项目:
package.json
这三个快捷指令
vite.config.js
内部集成了常见模块的插件,针对css等不需要单独额外处理
都是基于rollup插件去扩展的
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 自定义插件
import myVitePlugin from './plugins/myPlugin'// https://vitejs.dev/config/
export default defineConfig({plugins: [vue(), myVitePlugin()],test: {environment: 'jsdom',coverage: {reporter: ['text', 'json', 'html'],// 设置覆盖文件夹reportsDirectory: './coverage',// 检查每个文件的阈值perFile: true,// 设置代码覆盖率阈值lines: 75,functions: 75,branches: 75,statements: 75}}
})
自定义插件 -plugins/myPlugin.js
在工程当中,打印当前工程版本号
import path from 'path'
import fs from 'fs'//控制台打印当前工程版本号
export default function myVitePlugin() {let version, configreturn {name: 'my-vite-plugin',configResolved(resolvedConfig) {config = resolvedConfigconst pkgPath = path.resolve(config.root, 'package.json')const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))version = pkg.version},buildStart() {console.log('当前工程版本号:1.0.0')},transform(code, id) {if (id.endsWith('main.js')) {const info = `console.log('当前工程版本号:${version}')`return `${code}\n${info}\n`}}}
}
vite插件的相关钩子
- config 解析vite相关配置时候
- configResolved 解析配置之后的钩子
- configuerserver 配置开发服务器
- handlehotupdate 执行热更新时候的钩子
通用钩子
- options
- buildstart 开始创建
- transform 每个模块传入请求时调用
- buildend 构建结束
rspack - 推荐尝试使用
基于 rust 语言,实现的高性能前端构建工具
特性:兼容webpack生态
完全从webpack配置快速迁移到 rust 的技术体系当中,在构建速度上得到了显著的提升
rspack 官网
示例:通过 rsbuild 创建一个工程
pnpm create rsbuild@latest
类似 vite:
rsbuild 与 webpack区别:
- 语言优势,rust 语言编译时会转为机器码,少了解释执行的过程
- 多线程
rsbuild 与 vite 的区别: - vite 在生产环境依赖 rollup,在开发环境使用 esbuild+热更新,no-bundle按需下载的思想
turpopack 国外的
相对来说使用的比较少
基于 rust
turpopack 官网
由 Vercel 赞助的
vercel
可以一键去部署自己的项目,无需写git-action的配置,已经内置了这样的能力,做了CI/CD
相关文章:
前端工程化之新晋打包工具
新晋打包工具 新晋打包工具前端模块工具的发展历程分类初版构建工具grunt使用场景 gulp采用管道机制任务化配置与api简洁 现代打包构建工具基石--webpack基于webpack改进的构建工具rollup 推荐举例说明package.jsonrollup.config.mjsmy-extract-css-rollup-plugin.mjssrc/index…...
Python语言介绍
Python 是一种高级、通用、解释型的编程语言,由 Guido van Rossum 于 1991 年首次发布。其设计哲学强调代码的可读性和简洁性。 Python通过简洁的语法和强大的生态系统,成为当今最受欢迎的编程语言之一。 一、核心特点 Python 是一种解释型、面向对象、…...
关于 Spring Boot 部署到 Docker 容器的详细说明,涵盖核心概念、配置步骤及关键命令,并附上表格总结
以下是关于 Spring Boot 部署到 Docker 容器的详细说明,涵盖核心概念、配置步骤及关键命令,并附上表格总结: 1. Docker 核心概念 概念描述关系镜像(Image)预定义的只读模板,包含运行环境和配置(…...
Tomcat 服务频繁崩溃的排查方法
# Tomcat 服务频繁崩溃排查方法 当Tomcat服务频繁崩溃时,可以按照以下步骤进行系统化排查: ## 1. 检查日志文件 **关键日志位置**: - catalina.out (标准输出和错误) - catalina.log (主日志) - localhost.log (应用相关日志) - host-mana…...
分布式系统-脑裂,redis的解决方案
感谢你的反馈!很高兴能帮到你。关于你提到的“脑裂”(split-brain),这是一个分布式系统中的常见术语,尤其在像 Redis Cluster 这样的高可用集群中会涉及。既然你问到了,我会从头解释“脑裂”的含义、Redis …...
MySQL InnoDB 索引与B+树面试题20道
1. B树和B+树的区别是什么? 数据存储位置: B树:所有节点(包括内部节点和叶子节点)均存储数据。 B+树:仅叶子节点存储数据,内部节点仅存储键值(索引)。 叶子节点结构: B+树:叶子节点通过双向链表连接,支持高效的范围查询。 查询稳定性: B+树:所有查询必须走到叶子…...
深入解析 Spring AI Alibaba 多模态对话模型:构建下一代智能应用的实践指南
一、多模态对话模型的技术演进 1.1 从单一文本到多模态交互 现代AI应用正经历从单一文本交互到多模态融合的革命性转变。根据Gartner预测,到2026年将有超过80%的企业应用集成多模态AI能力。Spring AI Alibaba 对话模型体系正是为这一趋势量身打造,其技…...
2025年ESWA SCI1区TOP:动态分类麻雀搜索算法DSSA,深度解析+性能实测
目录 1.摘要2.麻雀搜索算法SSA原理3.孤立微电网经济环境调度4.改进策略5.结果展示6.参考文献7.代码获取 1.摘要 污染物排放对环境造成负面影响,而可再生能源的不稳定性则威胁着微电网的安全运行。为了在保障电力供应可靠性的同时实现环境和经济目标的平衡ÿ…...
MySQL Error Log
MySQL Error Log Error Log 的开启Error Log 查看Error Log 滚动 MySQL Error Log MySQL主从复制:https://blog.csdn.net/a18792721831/article/details/146117935 MySQL Binlog:https://blog.csdn.net/a18792721831/article/details/146606305 MySQL Ge…...
让DeepSeek API支持联网搜索
引子 DeepSeek官网注册的API token是不支持联网搜索的,这导致它无法辅助分析一些最新的情况或是帮忙查一下互联网上的资料。本文从实战角度提供一种稳定可靠的方法使得DeepSeek R1支持联网搜索分析。 正文 首先登录火山方舟控制台,https://www.volcen…...
SQL 语句说明
目录 数据库和数据表什么是 SQL 语言数据操作语言(DML)1、SELECT 单表查询通过 WHERE 对原始数据进行筛选通过 聚合函数 获取汇总信息通过 ORDER BY 对结果排序通过 GROUP BY 对数据进行分组通过 HAVING 对分组结果进行筛选 2、SELECT 多表查询3、INSERT…...
PostgreSQL内幕探索—基础知识
PostgreSQL内幕探索—基础知识 PostgreSQL(以下简称PG) 起源于 1986 年加州大学伯克利分校的 POSTGRES 项目,最初以对象关系模型为核心,支持高级数据类型和复杂查询功能。 1996 年更名为 PostgreSQL 并开源,逐…...
Springboot项目正常启动,访问资源却出现404错误如何解决?
我在自己的springboot项目中的启动类上同时使用了SprinBootApplication和ComponentScan注解, 虽然项目能够正常启动,但是访问资源后,返回404错误,随后在启动类中输出bean,发现controller创建失败: 而后我将ComponentScan去掉后资源就能访问到了. 原因 SprinBootApplication本身…...
MaxPooling层的作用(通俗解释)
MaxPooling层的作用(通俗解释) MaxPooling层是卷积神经网络中非常重要的组成部分,它的主要作用可以用以下几个简单的比喻来理解: 1. 信息压缩器(降维作用) 就像把一张高清照片缩小尺寸一样,M…...
0.DockerCE起步之Linux相关【完善中】
ubuntu用户组&权限&文件/目录 服务启停操作 sudo systemctl start docker # 启动服务3,4 sudo systemctl stop docker # 停止服务 sudo systemctl restart docker ps top 以下内容参考 Vim编辑器 Linux系统常用命令 管理Linux实例软件源 Cron定时任务 在Linux系统上…...
树莓派Pico C/C++ OpenOCD调试环境搭建(Windows)
树莓派Pico C/C OpenOCD调试环境搭建(Windows) 参考资料和背景 从上次树莓派Pico C/C 开发环境搭建(一键完成版)后,一直想找个合适调试器,最后测试了多种方案,还是使用另一块树莓派pico作为picoprobe 来调试比较方便,其中参考的…...
【图像生成之21】融合了Transformer与Diffusion,Meta新作Transfusion实现图像与语言大一统
论文:Transfusion: Predict the Next Token and Diffuse Images with One Multi-Modal Model 地址:https://arxiv.org/abs/2408.11039 类型:理解与生成 Transfusion模型是一种将Transformer和Diffusion模型融合的多模态模型,旨…...
《人件》第二章 办公环境
二、办公环境 电话铃不停的响,打印机维修人员顺道过来聊聊天,复印机不工作了,人事部不停催促更新的能力调查表,下午3点之前就要提交时间表…然后一天就这样过去了。 2.1 家具警察 人们怎么使用空间、需要的桌子空间多大、花多少小…...
哈希表系列一>存在重复元素II 存在重复元素I
目录 题目:解析:存在重复元素 II-->代码:存在重复元素-->代码: 题目: 链接: link 链接: link 解析: 存在重复元素 II–>代码: class Solution {public boolean containsNearbyDuplic…...
文献总结:AAAI2025-UniV2X-End-to-end autonomous driving through V2X cooperation
UniV2X 一、文章基本信息二、文章背景三、UniV2X框架1. 车路协同自动驾驶问题定义2. 稀疏-密集混合形态数据3. 交叉视图数据融合(智能体融合)4. 交叉视图数据融合(车道融合)5. 交叉视图数据融合(占用融合)6…...
LeetCode --- 444 周赛
题目列表 3507. 移除最小数对使数组有序 I 3508. 设计路由器 3509. 最大化交错和为 K 的子序列乘积 3510. 移除最小数对使数组有序 II 一、移除最小数对使数组有序 I & II 由于数组是给定的,所以本题的操作步骤是固定的,我们只要能快速模拟操作的过…...
单片机Day05---静态数码管
目录 一、原理图:编辑 二、思路梳理: 三:一些说明: 1.点亮方式: 2.数组: 3.数字与段码对应: 四:程序实现: 一、原理图: 二、思路梳理: …...
kernel32!GetQueuedCompletionStatus函数分析之返回值得有效性
第一部分://#define STATUS_SUCCESS 0x0返回值为0 } else { // // Set the completion status, capture the completion // information, deallocate the associated IRP, and // attempt to write the…...
gazebo 启动卡死的解决方法汇总
1. 排查显卡驱动是否正常安装 nvidia-smi # 英伟达显卡--------------------------------------------------------------------------------------- | NVIDIA-SMI 535.230.02 Driver Version: 535.230.02 CUDA Version: 12.2 | |------------------------…...
硬件设计-MOS管快速关断的原因和原理
目录 简介: 来源: MOS管快关的原理 先简单介绍下快关的原理: 同电阻时为什么关断时间会更长 小结 简介: 本章主要介绍MOS快速关断的原理和原因。 来源: 有人会问,会什么要求快速关断,而…...
塔能科技解节能密码,工厂成本“效益方程式”精准破题
在全球积极推进可持续发展战略的当下,各行业都在努力探索节能减排、绿色发展的新路径,对于工厂而言,节能早已不是锦上添花的选择,而已成为关乎企业生死存亡与长远发展的核心要素,是实现可持续运营的必由之路。塔能科技…...
swift ui基础
一个朴实无华的目录 今日学习内容:1.三种布局(可以相互包裹)1.1 vstack(竖直):先写的在上面1.1 hstack(水平):先写的在左边1.1 zstack(前后)&…...
格式工厂 v5.18最新免安装绿色便携版
前言 用它来转视频的时候,还能顺便给那些有点小瑕疵的视频修修补补,保证转出来的视频质量杠杠的。更厉害的是,它不只是转换那么简单,还能帮你把PDF合并成一本小册子,视频也能合并成大片,还能随心所欲地裁剪…...
CSPM认证对项目论证的范式革新:从合规审查到价值创造的战略跃迁
引言 在数字化转型浪潮中,全球企业每年因项目论证缺陷导致的损失高达1.7万亿美元(Gartner 2023)。CSPM(Certified Strategic Project Manager)认证体系通过结构化方法论,将传统的项目可行性评估升级为战略…...
TcxCustomCheckComboBoxProperties.EditValueFormat 值说明
TcxCheckStatesValueFormat 类枚举复选框状态对 edit 值的可能解释。以下选项可用。 价值 意义 cvf字幕 编辑值是一个字符串,其中包含两个由分号分隔的子字符串。分号前的子字符串包含灰显项目的标题列表。分号后面的子字符串包含已选中项目的标题列表。请注意&a…...
Spring Boot 测试详解,包含maven引入依赖、测试业务层类、REST风格测试和Mock测试
Spring Boot 测试详解 1. 测试依赖引入 Spring Boot 默认通过以下 Maven 依赖引入测试工具: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</s…...
【C语言】预处理(下)(C语言完结篇)
一、#和## 1、#运算符 这里的#是一个运算符,整个运算符会将宏的参数转换为字符串字面量,它仅可以出现在带参数的宏的替换列表中,我们可以将其理解为字符串化。 我们先看下面的一段代码: 第二个printf中是由两个字符串组成的&am…...
IIC通信协议
一、概述 IIC协议:是一种各种电子设备之间进行数据交换和通信的串行,半双工通信协议,主要用于近距离,低速的芯片之间的通信。 I2C协议采用双线结构传输数据,由一个数据线&#…...
SpringBoot原生实现分布式MapReduce计算(无第三方中间件版)
一、架构设计调整 核心组件替换方案: 注册中心 → 数据库注册表任务队列 → 数据库任务表分布式锁 → 数据库行级锁节点通信 → HTTP REST接口 二、数据库表结构设计 -- 节点注册表 CREATE TABLE compute_nodes (node_id VARCHAR(36) PRIMARY KEY,last_heartbea…...
02-libVLC的视频播放器:播放音视频文件以及网络流
libvlc_new(0, nullptr)功能:创建并初始化libVLC的核心实例,是使用所有libVLC功能的前提。 参数:第一个参数:参数数量(通常设为0)第二个参数:参数列表(通常为nullptr,表示使用默认配置)返回值:成功返回libvlc_instance_t*指针,失败返回nullptr。注意事项:可通过参…...
Autoware源码总结
Autoware源码网站 项目简介 教程 Autoware的整体架构如下图,主要包括传感器sensing、高精地图map data、车辆接口vehicle interface、感知perception(动态障碍物检测detection、跟踪tracking、预测prediction;交通信号灯检测detection、分类c…...
PowerBI 条形图显示数值和百分比
数据表: 三个度量值 销售额 SUM(销量表[销售量])//注意, 因为Y轴显示的产品,会被筛选,所以用ALLSELECTED来获取当前筛选条件下,Y轴显示的产品 百分比 FORMAT(DIVIDE([销售额],CALCULATE([销售额],ALLSELECTED(销量表[产品编码]))),"0…...
Sa-Token 自定义插件 —— SPI 机制讲解(一)
前言 博主在使用 Sa-Token 框架的过程中,越用越感叹框架设计的精妙。于是,最近在学习如何给 Sa-Token 贡献自定义框架。为 Sa-Token 的开源尽一份微不足道的力量。我将分三篇文章从 0 到 1 讲解如何为 Sa-Token 自定义一个插件,这一集将是前沿…...
基于 Termux 在移动端配置 Ubuntu 系统并搭建工作环境
本套方案主要参考了以下内容,并根据自身体验进行了修改。 【教程】用Termux搭建桌面级生产力环境Termux安装完整版Linux(Ubuntu)详细步骤 前言 自己的电脑太重,有时候外出不想带,平板生产力有有限。所以一直在折腾用平板替代电脑的事情。之前…...
JAVA SDK通过proxy对接google: GCS/FCM
前言:因为国内调用google相关api需要通过代理访问(不想设置全局代理),所以在代理这里经常遇到问题,先说一下结论 GCS 需要设置全局代理或自定义代理选择器, FCM sdk admin 在初始化firebaseApp时是支持设置的。 GCS: 开始时尝试在…...
JAVA EE_多线程-初阶(三)
我对未来没有底气 我也不知道当下该如何做 那就活着,活着就能把日子过下去 ---------陳長生. 1.多线程案例 1.1.单例模式 单例模式是常见的设计模式之一 设计模式:一些编程大佬制定的一些通用代码,再特定的场景下能套用进去,即…...
@PKU秋招互联网产品经理求职分享
从校园到职场 非常荣幸能够在毕业后两年半再次回到燕园。今天,我主要想和大家分享一下我在互联网行业的求职和工作经验。从最初面对职场的迷茫,到现在能够从容应对职场各种挑战,这一路走来积累了不少心得。互联网行业变化迅速,持续…...
uniapp日常总结--uniapp页面跳转方式
uniapp日常总结--uniapp页面跳转方式_uniapp 跳转-CSDN博客...
【能源节约管理系统行业树组件优化总结】
能源节约管理系统行业树组件优化总结 问题背景 在能源节约管理系统中,我们需要一个行业选择组件,以树形结构展示国民经济行业分类数据。由于行业数据量大且层级多,我们采用了懒加载的方式实现。然而,在编辑和详情模式下…...
青少年编程考试 CCF GESP图形化编程 二级认证真题 2025年3月
图形化编程 二级 2025 年 03 月 一、单选题(共 10 题,每题 3 分,共 30 分) 1、2025 年春节有两件轰动全球的事件,一个是 DeepSeek 横空出世,另一个是贺岁片《哪吒 2》票房惊人,入了全球票房榜…...
【Hadoop入门】Hadoop生态之Flume简介
1 什么是Flume? Flume是Hadoop生态系统中的一个高可靠、高性能的日志收集、聚合和传输系统。它支持在系统中定制各类数据发送方(Source)、接收方(Sink)和数据收集器(Channel),从而能…...
十六、Linus网络编程基础
1、Linux 网络的历史发展 早期阶段(1991–1995) 1991年:Linus Torvalds 发布 Linux 内核的初始版本(0.01),此时内核不支持网络功能,仅是一个单机操作系统。1992年:受 BSD …...
【激活函数:神经网络的“调味料】
1. 激活函数:神经网络的“调味料” 想象你在做菜: 没有激活函数:就像只用水煮食材,味道单调(只能拟合线性关系)。加入激活函数:像加了盐、糖、辣椒,让菜有酸甜苦辣(非线…...
006.Gitlab CICD流水线触发
文章目录 触发方式介绍触发方式类型 触发方式实践分支名触发MR触发tag触发手动人为触发定时任务触发指定文件变更触发结合分支及文件变更触发正则语法触发 触发方式介绍 触发方式类型 Gitlab CICD流水线的触发方式非常灵活,常见的有如下几类触发方式: …...
服务器远程端口详解
服务器远程端口详解 一、服务器远程端口的概念与作用 1. 端口的基本定义 服务器远程端口是计算机网络中用于标识不同应用程序或服务的逻辑接口。通过TCP/IP协议栈的"Socket"机制,计算机可以通过软件方式与其他设备建立通信通道。每个端口对应一个16位无…...