当前位置:网站首页>How to write vite plug-ins
How to write vite plug-ins
2022-06-23 13:23:00 【Yisu cloud】
How to write vite plug-in unit
This article mainly explains “ How to write vite plug-in unit ”, The explanation in the text is simple and clear , Easy to learn and understand , Next, please follow Xiaobian's ideas and go deeper slowly , Study and learn together “ How to write vite plug-in unit ” Well !
1. What is? vite plug-in unit
vite In fact, it is an original ES Module The new drive Web Develop front-end build tools .
vite plug-in unit It can be well extended vite Things you can't do by yourself , such as File image compression 、 Yes commonjs Support for 、 Pack progress bar wait .
2. Why write vite plug-in unit
I believe that every student here , Up to now, yes webpack You know the relevant configurations and common plug-ins of ;
vite As a new front-end building tool , It's still very young , It also has a lot of scalability , So why don't we join hands with it now ? Do something more meaningful to you, me and everyone ?
To write a plug-in , That must start with creating a project , Below vite Plug in common template You can write plug-ins directly in the future clone Use ;
Plug in common template github: Experience entrance
plug-in unit github: Experience entrance
It is recommended that the package manager use priority :pnpm > yarn > npm > cnpm
Cut a long story short , Let's go straight to work ~
establish vite Plug in common template
1. initialization
1.1 Create a folder and initialize : Initialize and follow the prompts
mkdir vite-plugin-progress && cd vite-plugin-progress && pnpm init
1.2 install typescript
pnpm i typescript @types/node -D
1.3 To configure tsconfig.json
{ "compilerOptions": { "module": "ESNext", "target": "esnext", "moduleResolution": "node", "strict": true, "declaration": true, "noUnusedLocals": true, "esModuleInterop": true, "outDir": "dist", "lib": ["ESNext"], "sourceMap": false, "noEmitOnError": true, "noImplicitAny": false }, "include": [ "src/*", "*.d.ts" ], "exclude": [ "node_modules", "examples", "dist" ]}1.4 install vite
// Get into package.json{ ... "devDependencies": { "vite": "*" } ...}2. To configure eslint and prettier( Optional )
install eslint
pnpm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
To configure .eslintrc: configure connections
install prettier ( Optional )
pnpm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev
To configure .prettierrc : configure connections
3. newly added src/index.ts entrance
import type { PluginOption } from 'vite';export default function vitePluginTemplate(): PluginOption { return { // The plug-in name name: 'vite-plugin-template', // pre Compared with post Execute first enforce: 'pre', // post // Indicates that they are available only in 'build' or 'serve' Called when in mode apply: 'build', // apply It can also be a function config(config, { command }) { console.log(' Here is config hook '); }, configResolved(resolvedConfig) { console.log(' Here is configResolved hook '); }, configureServer(server) { console.log(' Here is configureServer hook '); }, transformIndexHtml(html) { console.log(' Here is transformIndexHtml hook '); }, }}Among them vite The plug-in function hook will be explained in detail below ~
Come here , Then our basic template will be built , But let's think about it now , How should we run this plug-in ?
So we need to create some examples Example to run this code ;
4. establish examples Catalog
I have created three sets of projects here demo, Everybody directly copy That's it , I won't go into details here
vite-react
vite-vue2
vite-vue3
If your plug-in needs to run more demo, Create your own project ;
Then we need to configure examples The project under and the plug-in of the current root directory have been debugged ( Let's say examples/vite-vue3 For example ).
5. To configure examples/vite-vue3 project
modify examples/vite-vue3/package.json
{ ... "devDependencies": { ... "vite": "link:../../node_modules/vite", "vite-plugin-template": "link:../../" }}What the above means is :
To put examples/vite-vue3 In the project vite Version and root directory vite-plugin-template Consistent versions of ;
At the same time examples/vite-vue3 In the project vite-plugin-template Point to the plug-ins developed in your current root directory ;
Introducing plug-ins : examples/vite-vue3/vite.config.ts
import template from 'vite-plugin-template';export default defineConfig({ ... plugins: [vue(), template()], ...});install : cd examples/vite-vue3 && pnpm install
cd examples/vite-vue3 && pnpm install
Be careful :
examples/vite-vue2 and examples/vite-react The configuration of is consistent with this
reflection :
Come here , Let's think about it again , We put examples/vite-vue3 The items in are configured , But how should we run it ?
Go directly to examples/vite-vue3 Run in directory pnpm run build perhaps pnpm run dev ?
Obviously, this will not run successfully , Because our root directory src/index.ts It can't run directly , So we need to take .ts The file is escaped to .js file ;
So what do we do ?
So we have to try to use a light and small tool without configuration tsup 了 .
6. install tsup Configure run command
tsup Is a light, small and non configurable , from esbuild Supported build tools ;
At the same time, it can directly put .ts、.tsx Convert to a different format esm、cjs、iife Tools for ;
install tsup
pnpm i tsup -D
In the root directory package.json Middle configuration
{ ... "scripts": { "dev": "pnpm run build -- --watch --ignore-watch examples", "build": "tsup src/index.ts --dts --format cjs,esm", "example:react": "cd examples/vite-react && pnpm run build", "example:vue2": "cd examples/vite-vue2 && pnpm run build", "example:vue3": "cd examples/vite-vue3 && pnpm run build" }, ...}7. Development environment running
Development environment running : The real-time monitoring file is repackaged after modification ( Hot update )
pnpm run dev
function examples Any item in ( With vite-vue3 For example )
pnpm run example:vue3
Be careful :
If your plug-in will only be in build run , Then set up.
"example:vue3": "cd examples/vite-vue3 && pnpm run build" ;
On the contrary, it runs
pnpm run dev
Output :

Here you can Run while developing 了 , Youyuxi looked at it and said it was refreshing ~
8. Release
install bumpp Add version control and tag
pnpm i bumpp -D
To configure package.json
{ ... "scripts": { ... "prepublishOnly": "pnpm run build", "release": "npx bumpp --push --tag --commit && pnpm publish", }, ...}Run the release after developing the plug-in
# First step pnpm run prepublishOnly# The second step pnpm run release
So over here , our vite Plug in templates It's already written , You can clone directly vite-plugin-template Templates Use ;
If you are right about vite Plug-in hook and Achieve a real vite plug-in unit Interested can continue to look down ;
vite Plug-in hook hooks People
1. vite Unique hook
enforce : Values can be pre or post , pre Compared with post Execute first ;
apply : Values can be build or serve It can also be a function , Indicates that they are available only in build or serve Called when in mode ;
config(config, env) : Can be in vite Modify before being parsed vite Related configuration of . The hook receives the original user configuration config And a variable that describes the configuration environment env;
configResolved(resolvedConfig) : In parsing vite Call after configuration . Use this hook to read and store the final parsed configuration . When a plug-in needs to do something different according to the command it runs , It's very useful .
configureServer(server) : Mainly used to configure development The server , by dev-server (connect Applications ) Add custom middleware ;
transformIndexHtml(html) : transformation index.html Special hook for . The hook receives the current HTML String and conversion context ;
handleHotUpdate(ctx): Perform customization HMR to update , Can pass ws Send custom events to the client ;
2. vite And rollup The construction phase of the universal hook
options(options) : Called when the server starts : obtain 、 manipulation Rollup Options , Strictly speaking , It executes before it belongs to the construction phase ;
buildStart(options): Call each time you start a build ;
resolveId(source, importer, options): Called on each incoming module request , Create a custom confirmation function , Can be used to locate third-party dependencies ;
load(id): Called on each incoming module request , You can customize the loader , Can be used to return customized content ;
transform(code, id): Called on each incoming module request , It is mainly used to convert a single module ;
buildEnd(): Called at the end of the build phase , The end of construction here just means that all modules have been escaped ;
3. vite And rollup The output phase of the universal hook
outputOptions(options): Accept output parameters ;
renderStart(outputOptions, inputOptions): Every time bundle.generate and bundle.write It will be triggered when calling ;
augmentChunkHash(chunkInfo): To give chunk increase hash;
renderChunk(code, chunk, options): Translate single chunk Trigger when .rollup Output every chunk File will be called ;
generateBundle(options, bundle, isWrite): Calling bundle.write Trigger this immediately before hook;
writeBundle(options, bundle): Calling bundle.write after , be-all chunk After writing to the file , It will be called once finally writeBundle;
closeBundle(): Called when the server shuts down
4. Plug in hook function hooks Execution order of ( Here's the picture )

5. The order in which the plug-ins are executed
The alias processing Alias
User plug-in settings enforce: 'pre'
vite Core plug-ins
User plug-in is not set enforce
vite Build plug-ins
User plug-in settings enforce: 'post'
vite Build post plug-ins (minify, manifest, reporting)
Roll a hand vite plug-in unit
Let's say vite Pack progress bar Plug in as an example
inde.ts
import type { PluginOption } from 'vite';import colors from 'picocolors';import progress from 'progress';import rd from 'rd';import { isExists, getCacheData, setCacheData } from './cache';type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N;type PluginOptions = Merge< ProgressBar.ProgressBarOptions, { /** * total number of ticks to complete * @default 100 */ total?: number; /** * The format of the progress bar */ format?: string; }>;export default function viteProgressBar(options?: PluginOptions): PluginOption { const { cacheTransformCount, cacheChunkCount } = getCacheData() let bar: progress; const stream = options?.stream || process.stderr; let outDir: string; let transformCount = 0 let chunkCount = 0 let transformed = 0 let fileCount = 0 let lastPercent = 0 let percent = 0 return { name: 'vite-plugin-progress', enforce: 'pre', apply: 'build', config(config, { command }) { if (command === 'build') { config.logLevel = 'silent'; outDir = config.build?.outDir || 'dist'; options = { width: 40, complete: '\u2588', incomplete: '\u2591', ...options }; options.total = options?.total || 100; const transforming = isExists ? `${colors.magenta('Transforms:')} :transformCur/:transformTotal | ` : '' const chunks = isExists ? `${colors.magenta('Chunks:')} :chunkCur/:chunkTotal | ` : '' const barText = `${colors.cyan(`[:bar]`)}` const barFormat = options.format || `${colors.green('Bouilding')} ${barText} :percent | ${transforming}${chunks}Time: :elapseds` delete options.format; bar = new progress(barFormat, options as ProgressBar.ProgressBarOptions); // not cache: Loop files in src directory if (!isExists) { const readDir = rd.readSync('src'); const reg = /\.(vue|ts|js|jsx|tsx|css|scss||sass|styl|less)$/gi; readDir.forEach((item) => reg.test(item) && fileCount++); } } }, transform(code, id) { transformCount++ // not cache if(!isExists) { const reg = /node_modules/gi; if (!reg.test(id) && percent < 0.25) { transformed++ percent = +(transformed / (fileCount * 2)).toFixed(2) percent < 0.8 && (lastPercent = percent) } if (percent >= 0.25 && lastPercent <= 0.65) { lastPercent = +(lastPercent + 0.001).toFixed(4) } } // go cache if (isExists) runCachedData() bar.update(lastPercent, { transformTotal: cacheTransformCount, transformCur: transformCount, chunkTotal: cacheChunkCount, chunkCur: 0, }) return { code, map: null }; }, renderChunk() { chunkCount++ if (lastPercent <= 0.95) isExists ? runCachedData() : (lastPercent = +(lastPercent + 0.005).toFixed(4)) bar.update(lastPercent, { transformTotal: cacheTransformCount, transformCur: transformCount, chunkTotal: cacheChunkCount, chunkCur: chunkCount, }) return null }, closeBundle() { // close progress bar.update(1) bar.terminate() // set cache data setCacheData({ cacheTransformCount: transformCount, cacheChunkCount: chunkCount, }) // out successful message stream.write( `${colors.cyan(colors.bold(`Build successful. Please see ${outDir} directory`))}` ); stream.write('\n'); stream.write('\n'); } }; /** * run cache data of progress */ function runCachedData() { if (transformCount === 1) { stream.write('\n'); bar.tick({ transformTotal: cacheTransformCount, transformCur: transformCount, chunkTotal: cacheChunkCount, chunkCur: 0, }) } transformed++ percent = lastPercent = +(transformed / (cacheTransformCount + cacheChunkCount)).toFixed(2) }}cache.ts
import fs from 'fs';import path from 'path';const dirPath = path.join(process.cwd(), 'node_modules', '.progress');const filePath = path.join(dirPath, 'index.json');export interface ICacheData { /** * Transform all count */ cacheTransformCount: number; /** * chunk all count */ cacheChunkCount: number}/** * It has been cached * @return boolean */export const isExists = fs.existsSync(filePath) || false;/** * Get cached data * @returns ICacheData */export const getCacheData = (): ICacheData => { if (!isExists) return { cacheTransformCount: 0, cacheChunkCount: 0 }; return JSON.parse(fs.readFileSync(filePath, 'utf8'));};/** * Set the data to be cached * @returns */export const setCacheData = (data: ICacheData) => { !isExists && fs.mkdirSync(dirPath); fs.writeFileSync(filePath, JSON.stringify(data));};Thank you for reading , That's all “ How to write vite plug-in unit ” Content. , After learning this article , I believe everyone knows how to write vite I have a deeper understanding of the problem of plug-ins , The specific use needs to be verified by practice . This is billion speed cloud , Xiaobian will push you articles with more relevant knowledge points , Welcome to your attention !
边栏推荐
- R language uses the polR function of mass package to build an ordered multi classification logistic regression model, and uses the summary function to obtain the summary statistical information of the
- Playing in Singapore in the hot summer: an inventory of indoor attractions and good places for night trips
- 64 channel PCM telephone optical transceiver 64 channel telephone +2-channel 100M Ethernet telephone optical transceiver 64 channel telephone PCM voice optical transceiver
- R语言dplyr包filter函数过滤dataframe数据中指定数据列的内容包含指定字符串的数据行、基于grepl函数
- R language uses the multinom function of NNET package to build a disordered multi classification logistic regression model, uses regression coefficients and their standard errors to calculate the valu
- The filter function of dplyr package in R language filters the data rows containing the specified string in the specified data column of dataframe data based on the grepl function
- Esp32-c3 introductory tutorial problems ⑧ - blufi_ example. c:244: undefined reference to `esp_ ble_ gap_ start_ advertising
- R language uses the polR function of mass package to build an ordered multi classification logistic regression model, and uses exp function and coef function to obtain the corresponding odds ratio of
- Lm05 former VIX (second generation product)
- Interview question: for example, how do you do interface testing at work?
猜你喜欢

Can cold plate, submerged and spray liquid cooling lead the development of high-performance computing?

Germancreditdata of dataset: a detailed introduction to the introduction, download and use of germancreditdata dataset

Go write file permission WriteFile (filename, data, 0644)?

Go write permissions to file writefile (FileName, data, 0644)?

Filtre de texte en ligne inférieur à l'outil de longueur spécifiée

MySQL使用ReplicationConnection導致的連接失效分析與解决

2 万字 + 30 张图 |MySQL 日志:undo log、redo log、binlog 有什么用?

Hanyuan high tech USB3.0 optical transceiver USB industrial touch screen optical transceiver USB3.0 optical fiber extender USB3.0 optical fiber transmitter

在線文本過濾小於指定長度工具

You call this shit MQ?
随机推荐
HomeKit支持matter协议,这背后将寓意着什么?
Hanyuan hi tech 1-way uncompressed 4k-dvi optical transceiver 4K HD uncompressed DVI to optical fiber 4k-dvi HD video optical transceiver
Getting started with reverse debugging - learn about PE structure files
.Net怎么使用日志框架NLog
Go write file permission WriteFile (filename, data, 0644)?
AssetBundle resource management
Has aaig really awakened its AI personality after reading the global June issue (Part 1)? Which segment of NLP has the most social value? Get new ideas and inspiration ~
理财产品长期是几年?新手最好买长期还是短期?
Analysis and solution of connection failure caused by MySQL using replicationconnection
Androd Gradle模块依赖替换如何使用
互联网技术发展内卷后的出路——iVX的诞生
js: 获取页面最大的zIndex(z-index)值
64 channel PCM telephone optical transceiver 64 channel telephone +2-channel 100M Ethernet telephone optical transceiver 64 channel telephone PCM voice optical transceiver
Cloud native essay deep understanding of ingress
R language is used to build ordered multi classification logistic regression model, ordinal or. The display function obtains the summary statistical information of the ordered logistic regression mode
R语言dplyr包mutate_all函数将dataframe中的所有数值数值列(变量)乘以某一固定值并生成新的数据列,为新的数据列(变量)指定自定义后缀名称
What should testers do if the requirements need to be changed when the project is half tested?
MySQL使用ReplicationConnection導致的連接失效分析與解决
快速了解常用的非对称加密算法,再也不用担心面试官的刨根问底
逆向调试入门-了解PE结构文件