前端工程化之新晉打包工具

新晉打包工具

  • 新晉打包工具
    • 前端模塊工具的發展歷程
    • 分類
    • 初版構建工具
      • 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 語言實現的,使用多線程
  1. 簡歷中做一些優化,針對 webpack 做一些常規的優化,像進行分包,還有像通過引入cache提升構建速度,像leo-plugins等方式,只是針對webpack本身所作的優化,但是現在
    webpack+babel 已經具備了性能瓶頸 => 優化措施:webpack+swc
    babel 對標 => swc
    babel-loader => swc-loader

  2. 文件比較多,使用 babel-loader 的話,需要經歷 翻譯、ast 是比較耗時的
    使用swc的話,性能會得到質的飛躍

  3. swc官方網站

  4. 性能表現原因:

    • rust 語言編寫,編譯時確定運行的行為,不像js是解釋執行,解釋成機器語言再執行機器語言。rust 是多線程的這樣的一個能力
  5. 功能覆蓋
    SWC 主要對 js 代碼快速轉換,核心將 es6+代碼轉換成 es5或者其他代碼,在這過程中會進行代碼壓縮優化等相關的一些操作,比如swc能很好的處理箭頭函數模板字符串解構賦值等es6+特性的轉換,還有針對ts語言tsx語言等語言的處理,成熟度也是可以的

  6. 使用:簡單轉換代碼
    @swc/core @swc/cli

    npx 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本質是解釋型語言,執行代碼的時候需要一邊將源碼翻譯成機器語言,一邊調度執行。

  1. go編寫程序,是編譯型語言,少了動態解釋過程

  2. 多線程
    go語言具備多線程能力,將所有的包都進行深度開發,因為JS是單線程,雖然也引入了webworker 做一些多線程的事情,但是還是有一些限制,比如說,go的多個線程之間是可以共享當前進程的內存空間,但是JS的webworker是不能共享進程內存空間的,如果想要數據共享的話,需要通過 postmessage 進行通信,但是這樣的話,效率也比較低下的。因此,這也是JS的限制
    => 更高效的利用內存使用率 => 達到了更高的運行性能

  3. 全量定制
    比如,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結構的轉換,進而提升內存利用率

  4. 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項目:

  1. 加載html,html中引入了main.js
    在這里插入圖片描述
    還會引入 @vite/client,實現熱更新
    在這里插入圖片描述
  2. 加載client資源(熱更新)
    監聽消息
    在這里插入圖片描述
    handleMessage方法:
    在這里插入圖片描述
    在websocket中能看到payload.type,connect是建聯,update是更新操作,等等。

先是建聯:
在這里插入圖片描述
更改 頁面文字:
在這里插入圖片描述
websocket會有update更新
在這里插入圖片描述

類型是 js-update的話,會調用隊列:
在這里插入圖片描述
最終會發起 App.vue請求
App.vue請求會帶著時間戳,不會復用之前的,避免了緩存的影響,就會拿到更改之后的數據替換之前的內容
在這里插入圖片描述

  1. 加載main.js,引入了vue.js,style.css,等
    在這里插入圖片描述

  2. 加載vue.js,style.css等,比如,style.css使用css插件做處理,創建style標簽用在header當中
    在這里插入圖片描述
    在這里插入圖片描述

為什么vite之前沒有,到2021年后才有這樣的開發鏈路呢?
  1. http2.x 支持,多路復用
    之前webpack不拆包,將所有的都打包到一個bundle當中,熱更新重新走整個鏈路的流程,最終形成bundle,然后再更新這個bundle,會受體積影響
    現在都是使用websocket,支持單文件的熱更新
    多路復用
    http1.0 會對單個域名有tcp請求的限制,限制 6-8 tcp請求鏈接的數量,因此,將多個文件合并到一個文件當中進行處理,避免限制對有些請求發送不出去
    http2.x 有多路復用,同一個域名下對請求并發限制很大,10個,50個,100個同時請求服務器下的多個資源
  2. 瀏覽器支持 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區別:

  1. 語言優勢,rust 語言編譯時會轉為機器碼,少了解釋執行的過程
  2. 多線程
    rsbuild 與 vite 的區別:
  3. vite 在生產環境依賴 rollup,在開發環境使用 esbuild+熱更新,no-bundle按需下載的思想

turpopack 國外的

相對來說使用的比較少

基于 rust
turpopack 官網

由 Vercel 贊助的
vercel
可以一鍵去部署自己的項目,無需寫git-action的配置,已經內置了這樣的能力,做了CI/CD

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/78760.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/78760.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/78760.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

ai軟件UI自動化

在AI與UI自動化結合的場景中,通常涉及計算機視覺(CV)、自然語言處理(NLP)和機器學習(ML)等技術。以下是實現AI驅動UI自動化的關鍵方向、工具和步驟: ?一、核心應用場景? ?元素定位增強? ?問題?:傳統工具依賴XPath/CSS選擇器,易因UI變化失效。?AI方案?:CV識別…

關于 C++ 中 cin 對象和 EOF 的詳細解釋

【DeepSeek提問】 給解釋一下下面這段話&#xff08;C編程&#xff09; cin是 iostream 類的一個對象實例&#xff0c;如果輸入正常&#xff0c; cin 將返回本身。 舉個例子&#xff1a;cin>x>>y, 如果 cin>>x 讀入正常&#xff0c;那么將返回cin, 相當于后面繼…

Vue 3 和 Vue 2 的區別及優點

Vue.js 是一個流行的 JavaScript 框架&#xff0c;廣泛用于構建用戶界面和單頁應用。自 Vue 3 發布以來&#xff0c;很多開發者開始探索 Vue 3 相較于 Vue 2 的新特性和優勢。Vue 3 引入了許多改進&#xff0c;優化了性能、增強了功能、提升了開發體驗。本文將詳細介紹 Vue 2 和…

【特權FPGA】之UART串口

0.簡介 通用異步收發器(Universal Asynchronous Receiver&#xff0f;Transmitter&#xff0c;UART)可以和各種標準串行接口&#xff0c;如RS 232和RS 485等進行全雙工異步通信&#xff0c;具有傳輸距離遠、成本低、可靠性高等優點。一般UART由專用芯片如8250&#xff0c;1645…

Vue3中watch監視reactive對象方法詳解

在Vue3中&#xff0c;使用watch監視reactive對象時&#xff0c;需根據監視的目標選擇合適的方法。以下是詳細的步驟和說明&#xff1a; 1. 監視整個reactive對象 自動深度監視&#xff1a;直接監視reactive對象時&#xff0c;Vue3會默認啟用深度監視&#xff0c;無需設置deep:…

如何制定性能調優策略

目錄 性能測試攻略 微基準性能測試 宏基準性能測試 熱身問題 多 JVM 情況下的影響 合理分析結果&#xff0c;制定調優策略 推薦閱讀 性能測試攻略 性能測試是提前發現性能瓶頸&#xff0c;保障系統性能穩定的必要措施。下面我先給你介紹兩種常用 的測試方法&#xff0c;幫…

HarmonyOS-ArkUI V2裝飾器@Local裝飾器:組件內部狀態

@Local裝飾器的作用 @Local裝飾器是用來裝飾組件內的狀態的。而且它修飾的變量可以成為數據源。Local裝飾器,作用跟名字差不多,重點突出了“本地”的特性,也就是使用的范圍僅僅限制在組件內部。且它在初始化的時候必須是在本地進行初始化的,不能在外部組件,同時也禁止了外…

Linux線程屬性與多線程開發:API詳解與實戰代碼解析

Linux 線程的屬性 線程池 多線程的創建 線程的屬性 引入 我們設想一個場景&#xff0c;使用pthread_detach時&#xff0c;發現線程早就已經結束了&#xff0c;這時候pthread_detach還能正常發揮清理線程的 獨有空間 的作用嗎&#xff1f; 答案是可以的&#xff0c;但是這難…

測試第二課-------測試分類

作者前言 &#x1f382; ??????&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ?&#x1f382; 作者介紹&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

MySQL安裝實戰分享

一、在 Windows 上安裝 MySQL 1. 下載 MySQL 安裝包 訪問 MySQL 官方下載頁面。選擇適合你操作系統的版本。一般推薦下載 MySQL Installer。 2. 運行安裝程序 雙擊下載的安裝文件&#xff08;例如 mysql-installer-community-<version>.msi&#xff09;。如果出現安全…

數據庫預熱

介紹 Database Warm-up &#x1f9e0; 一句話理解 數據庫是在應用啟動階段&#xff0c;提前建立數據庫連接 或 執行輕量 SQL 操作&#xff0c;從而 加快首個請求的響應速度 的一種優化手段 &#x1f3af; 為什么需要數據庫預熱&#xff1f; 當 FastAPI 或其他 Web 服務剛啟…

SearXNG

SearXNG 什么是 SearXNG &#xff1f;說白了&#xff0c;其實就是一個免費開源的搜索引擎。那為什么要本地安裝它呢&#xff1f; 看它官網的解釋(翻譯)&#xff0c;當然&#xff0c;其中官方也有一篇文檔解釋了為什么需要部署使用私有示例&#xff1a;為什么使用私有實例&…

js 顏色轉換分析

一、十六進制轉RGB function hexToRgba(hex) {// 移除 # 字符hex hex.replace(#, );// 處理簡寫形式如 #fffif (hex.length 3) {hex hex[0] hex[0] hex[1] hex[1] hex[2] hex[2];}// 轉換為十進制const r parseInt(hex.substring(0, 2), 16); // 截圖前兩位&#xff0…

智能資源管理機制-重傳機制

一、發送端資源管理的核心機制 1. 滑動窗口&#xff08;Sliding Window&#xff09; 這是TCP協議的核心優化設計&#xff1a; 窗口動態滑動&#xff1a;發送端不需要保留所有已發送的分組&#xff0c;只需維護一個"發送窗口"窗口大小&#xff1a;由接收方通告的接…

基于SSM+Layui畢業設計選題系統源碼

項目介紹 基于SSM+Layui畢業設計選題系統源碼,可以作為課程設計項目參考,該系統分為三個角色: 管理員:用戶管理(對學生和老師的信息進行維護),統計分析(對老師課題情況以及學生選題情況信息進行維護),修改密碼 老師:個人信息維護,畢業設計題目管理,報名學生管理…

通過uri獲取文件路徑手機適配

青銅版本 return contentResolver.query(this, arrayOf(MediaStore.MediaColumns.DATA), null, null).let {if (it?.moveToFirst() true) {val columnIndex it.getColumnIndex(MediaStore.MediaColumns.DATA)val path it.getString(columnIndex)it.close()return path}&quo…

vue模擬撲克效果

vue模擬撲克效果 效果圖&#xff1a; step1:C:\Users\wangrusheng\PycharmProjects\untitled18\src\views\Home.vue <template><div class"poker-container"><!-- 使用復合數據對象實現雙行顯示 --><divv-for"(card, index) in POKER_…

基礎數學:圖論與信息論

微積分與概率論由此進&#xff1a;基礎數學&#xff1a;微積分和概率與統計-CSDN博客 線代與優化理論由此進&#xff1a;基礎數學&#xff1a;線性代數與優化理論-CSDN博客 數值分析與離散數學由此進&#xff1a;基礎數學&#xff1a;數值分析與離散數學-CSDN博客 四、圖論與…

構建智能期貨交易策略分析應用:MCP與AI的無縫集成

引言 隨著金融科技的快速發展&#xff0c;數據驅動的交易決策已成為期貨交易領域的重要趨勢。本文將深入探討一個結合了Model Content Protocol (MCP)和AI技術的期貨交易策略分析應用——Futures MCP。該應用不僅提供了豐富的技術分析工具&#xff0c;還通過MCP協議與大型語言…

0x02.Redis 集群的實現原理是什么?

回答重點 Redis 集群&#xff08;Redis cluster&#xff09;是通過多個 Redis 實例組成的&#xff0c;每個主節點實例負責存儲部分的數據&#xff0c;并且可以有一個或多個從節點作為備份。 具體是采用哈希槽&#xff08;Hash Slot&#xff09;機制來分配數據&#xff0c;將整…