Ainda não sabe como escrever um plugin do Vite?
Agora que as ferramentas Vite estão se tornando populares, podemos fazer algo significativo, como escrever um plugin do Vite, o que você acha?
Acontece que podemos aproveitar a fase inicial do ecossistema de plugins do Vite, criar um plugin que nos agrade, agrade aos líderes e à comunidade, e crescer juntos com ele.
Se você tem interesse no Vite, pode acessar a coluna: "Vite do início ao domínio"
Neste artigo você aprenderá
Como criar um template de plugin do Vite
O papel de cada hook do plugin do Vite
Ordem de execução dos hooks do plugin do Vite
Como escrever seu próprio plugin
Conheça os plugins do Vite
1. O que é um plugin do Vite
O Vite é, na verdade, uma nova ferramenta de desenvolvimento web front-end impulsionada por ES Module nativo.
O plugin do Vite pode estender muito bem as funcionalidades que o próprio Vite não consegue fazer, como compressão de arquivos e imagens, suporte a CommonJS, barra de progresso de empacotamento, entre outros.
2. Por que escrever um plugin do Vite
Acredito que todos aqui já estejam familiarizados com as configurações relevantes do webpack e plugins comuns;
Como uma nova ferramenta de build front-end, o Vite ainda é jovem e tem muita extensibilidade, então por que não crescemos juntos com ele agora? Vamos fazer algo mais significativo para você, para mim e para todos?
Experiência rápida
Se você quer escrever um plugin, precisa começar criando um projeto. O template geral de plugin do Vite abaixo pode ser usado diretamente via clone quando você escrever um plugin no futuro;
Template geral de plugin no GitHub: entrada de experiência
Plugin no GitHub: entrada de experiência
Gerenciador de pacotes recomendado por prioridade: pnpm > yarn > npm > cnpm
Sem mais delongas, vamos começar~
Criar um template genérico de plugin do Vite
1. Inicializar
1.1 Criar uma pasta e inicializá-la: Basta seguir as instruções para inicializar
mkdir vite-plugin-progress && cd vite-plugin-progress && pnpm init
1.2 Instalar TypeScript
pnpm i typescript @types/node -D
1.3 Configurar 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 Instalar o Vite
// enter package.json
{
...
"devDependencies": {
"vite": "*"
}
...
}
2. Configurar eslint e prettier (opcional)
instalar eslint
pnpm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
configurar .eslintrc: configurar a conexão
Instalar prettier (opcional)
pnpm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev
configurar .prettierrc: configurar a conexão
3. Adicionar entrada src/index.ts
import type { PluginOption } from 'vite';
export default function vitePluginTemplate(): PluginOption {
return {
// plugin name
name: 'vite-plugin-template',
// pre will be executed before post
enforce: 'pre', // post
// Indicate that they are only called in 'build' or 'serve' mode
apply: 'build', // apply can also be a function
config(config, { command }) {
console.log('here is the config hook');
},
configResolved(resolvedConfig) {
console.log('here is the configResolved hook');
},
configureServer(server) {
console.log('here is the configureServer hook');
},
transformIndexHtml(html) {
console.log('here is the transformIndexHtml hook');
},
}
}
Os hooks de função do plugin do Vite serão explicados em detalhes abaixo~
Neste ponto, nosso template básico está criado, mas vamos pensar agora: como devemos executar este plugin?
Então precisamos criar alguns exemplos para executar este código;
4. Criar o diretório examples
Criei três conjuntos de demos de projetos aqui. Você pode copiá-los diretamente. Não vou apresentá-los em detalhes aqui.
vite-react
vite-vue2
vite-vue3
Se seu plugin precisar executar mais demos, basta criar o projeto você mesmo;
Então precisamos configurar o projeto em examples para fazer uma depuração conjunta com o plugin no diretório raiz atual (tomando examples/vite-vue3 como exemplo abaixo).
5. Configurar o projeto examples/vite-vue3
Modificar examples/vite-vue3/package.json
{
...
"devDependencies": {
...
"vite": "link:../../node_modules/vite",
"vite-plugin-template": "link:../../"
}
}
O acima significa:
Tornar a versão do Vite no projeto examples/vite-vue3 consistente com a versão no diretório raiz vite-plugin-template;
Ao mesmo tempo, apontar o vite-plugin-template no projeto examples/vite-vue3 para o plugin desenvolvido no diretório raiz atual;
Introduzir o plugin: examples/vite-vue3/vite.config.ts
import template from 'vite-plugin-template';
export default defineConfig({
...
plugins: [vue(), template()],
...
});
Instalar: cd examples/vite-vue3 && pnpm install
cd examples/vite-vue3 && pnpm install
Nota: a configuração de examples/vite-vue2 e examples/vite-react é consistente com esta
reflexão:
Neste ponto, vamos pensar novamente. Configuramos o projeto em examples/vite-vue3, mas como devemos executá-lo?
Ir diretamente ao diretório examples/vite-vue3 e executar pnpm run build ou pnpm run dev?
Obviamente isso não funcionará, porque o src/index.ts no nosso diretório raiz não pode ser executado diretamente, então precisamos converter o arquivo .ts em um arquivo .js;
Então, como lidamos com isso?
Então temos que tentar usar uma ferramenta pequena e sem configuração: tsup.
6. Instalar tsup e configurar comando de execução
tsup é uma ferramenta de build leve e sem configuração, suportada pelo esbuild;
Ao mesmo tempo, pode converter diretamente .ts, .tsx em ferramentas de diferentes formatos: esm, cjs, iife;
instalar tsup
pnpm i tsup -D
Configurado no package.json no diretório raiz
{
...
"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. Execução no ambiente de desenvolvimento
Operação no ambiente de desenvolvimento: monitoramento em tempo real de modificações de arquivos e reempacotamento (hot reload)
pnpm run dev
Executar qualquer projeto em examples (tomando vite-vue3 como exemplo)
pnpm run example:vue3
Aviso:
Se seu plugin só será executado no momento do build, defina "example:vue3": "cd examples/vite-vue3 && pnpm run build";
Caso contrário, execute pnpm run dev
saída:
A partir daqui, você pode executar enquanto desenvolve. A Yuxi disse que achou legal quando viu~
8. Publicar
Instalar bumpp para adicionar controle de versão e tags
pnpm i bumpp -D
configurar package.json
{
...
"scripts": {
...
"prepublishOnly": "pnpm run build",
"release": "npx bumpp --push --tag --commit && pnpm publish",
},
...
}
Executar publicação após desenvolver o plugin
# first step
pnpm run prepublishOnly
# second step
pnpm run release
Pronto, nosso template de plugin do Vite foi escrito. Você pode clonar diretamente o template vite-plugin-template para usar;
Se você tem interesse nos hooks de plugin do Vite e em implementar um plugin real do Vite, pode continuar lendo abaixo;
Hooks de plugin do Vite
1. Hooks exclusivos do Vite
enforce: o valor pode ser pre ou post, pre será executado antes de post;
apply: o valor pode ser build ou serve ou uma função, especificando que são chamados apenas no modo build ou serve;
config(config, env): Você pode modificar a configuração relacionada ao Vite antes de ele ser analisado. O hook recebe a configuração original do usuário config e uma variável env descrevendo o ambiente de configuração;
configResolved(resolvedConfig): Chamado após a configuração do Vite ser resolvida. Use este hook para ler e armazenar a configuração final resolvida. É útil quando um plugin precisa fazer algo diferente dependendo do comando executado.
configureServer(server): usado principalmente para configurar o servidor de desenvolvimento e adicionar middleware personalizado ao dev-server (aplicação connect);
transformIndexHtml(html): Hook dedicado para transformar index.html. O hook recebe a string HTML atual e o contexto de conversão;
handleHotUpdate(ctx): Executar atualização HMR personalizada, você pode enviar eventos personalizados ao cliente através de ws;
2. Fase de construção de hooks comuns do Vite e rollup
options(options): chamado quando o servidor inicia: obter e manipular as opções do Rollup; estritamente falando, é executado antes da fase de build;
buildStart(options): chamado toda vez que um build inicia;
resolveId(source, importer, options): chamado para cada solicitação de módulo recebida, cria uma função de confirmação personalizada, que pode ser usada para localizar dependências de terceiros;
load(id): Chamado para cada solicitação de módulo recebida, o loader pode ser personalizado e pode ser usado para retornar conteúdo personalizado;
transform(code, id): chamado para cada solicitação de módulo recebida, usado principalmente para transformar um único módulo;
buildEnd(): Chamado após o fim da fase de build, onde o fim do build significa apenas que todos os módulos foram convertidos;
3. Fase de saída dos hooks gerais do Vite e rollup
outputOptions(options): aceita parâmetros de saída;
renderStart(outputOptions, inputOptions): será disparado toda vez que bundle.generate e bundle.write forem chamados;
augmentChunkHash(chunkInfo): usado para adicionar hash ao chunk;
renderChunk(code, chunk, options): Disparado quando um único chunk é traduzido. O rollup é chamado quando cada arquivo chunk é gerado;
generateBundle(options, bundle, isWrite): dispara este hook imediatamente antes de chamar bundle.write;
writeBundle(options, bundle): Após chamar bundle.write, depois que todos os chunks forem escritos no arquivo, writeBundle será chamado no final;
closeBundle(): chamado quando o servidor é fechado
4. Ordem de execução dos hooks de função do plugin (conforme mostrado abaixo)
5. Ordem de execução dos plugins
Tratamento de Alias
Plugin do usuário com enforce: 'pre'
Plugin principal do Vite
Plugin do usuário sem enforce definido
Plugin de build do Vite
Plugin do usuário com enforce: 'post'
Plugins pós-build do Vite (minify, manifest, relatórios)
Criar um plugin do Vite na prática
A seguir, tomamos o plugin de barra de progresso de empacotamento do Vite como exemplo;
Endereço do plugin: GitHub. Se gostar, fique à vontade para dar uma estrela ⭐️
O plugin foi oficialmente incluído pelo Vite na documentação oficial: link
Como o foco deste artigo não é o processo detalhado de implementação deste plugin, este artigo apenas colará o código-fonte para sua referência. A introdução detalhada será explicada no próximo artigo, aguarde!
index.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 = Pick>;
type Merge = Omit> & 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,
...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');
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(' ');
stream.write(' ');
}
};
/**
* run cache data of progress
*/
function runCachedData() {
if (transformCount === 1) {
stream.write(' ');
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));
};
por fim
Esta série terá atualizações contínuas. Em relação a toda a coluna "Vite do Iniciante ao Domínio", explicarei principalmente pelos seguintes aspectos, aguarde!!!
Pessoal, vocês viram tudo até aqui, por que não curtiram 👍.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} Categoria: Front-end Tags: Front-end Vite Artigos incluídos na coluna:
Vite do início ao domínio
Vite (pronunciado de forma semelhante a [weɪt], leve, significado de leveza) é uma ferramenta de build front-end para desenvolvimento web impulsionada por ES Module nativo.
Possui as seguintes características:
💡 Início de serviço extremamente rápido;
⚡️ Hot reload leve e rápido;
🛠️ Funções ricas;
📦 Build otimizado;
🔩 Plugin universal;
🔑 API totalmente tipada.
Acontece que podemos aproveitar a fase inicial do ecossistema de plugins do Vite, criar um plugin que nos agrade, agrade aos líderes e à comunidade, e crescer juntos com ele.
Se você tem interesse no Vite, pode acessar a coluna: "Vite do início ao domínio"
Neste artigo você aprenderá
Como criar um template de plugin do Vite
O papel de cada hook do plugin do Vite
Ordem de execução dos hooks do plugin do Vite
Como escrever seu próprio plugin
Conheça os plugins do Vite
1. O que é um plugin do Vite
O Vite é, na verdade, uma nova ferramenta de desenvolvimento web front-end impulsionada por ES Module nativo.
O plugin do Vite pode estender muito bem as funcionalidades que o próprio Vite não consegue fazer, como compressão de arquivos e imagens, suporte a CommonJS, barra de progresso de empacotamento, entre outros.
2. Por que escrever um plugin do Vite
Acredito que todos aqui já estejam familiarizados com as configurações relevantes do webpack e plugins comuns;
Como uma nova ferramenta de build front-end, o Vite ainda é jovem e tem muita extensibilidade, então por que não crescemos juntos com ele agora? Vamos fazer algo mais significativo para você, para mim e para todos?
Experiência rápida
Se você quer escrever um plugin, precisa começar criando um projeto. O template geral de plugin do Vite abaixo pode ser usado diretamente via clone quando você escrever um plugin no futuro;
Template geral de plugin no GitHub: entrada de experiência
Plugin no GitHub: entrada de experiência
Gerenciador de pacotes recomendado por prioridade: pnpm > yarn > npm > cnpm
Sem mais delongas, vamos começar~
Criar um template genérico de plugin do Vite
1. Inicializar
1.1 Criar uma pasta e inicializá-la: Basta seguir as instruções para inicializar
mkdir vite-plugin-progress && cd vite-plugin-progress && pnpm init
1.2 Instalar TypeScript
pnpm i typescript @types/node -D
1.3 Configurar 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 Instalar o Vite
// enter package.json
{
...
"devDependencies": {
"vite": "*"
}
...
}
2. Configurar eslint e prettier (opcional)
instalar eslint
pnpm i eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev
configurar .eslintrc: configurar a conexão
Instalar prettier (opcional)
pnpm i prettier eslint-config-prettier eslint-plugin-prettier --save-dev
configurar .prettierrc: configurar a conexão
3. Adicionar entrada src/index.ts
import type { PluginOption } from 'vite';
export default function vitePluginTemplate(): PluginOption {
return {
// plugin name
name: 'vite-plugin-template',
// pre will be executed before post
enforce: 'pre', // post
// Indicate that they are only called in 'build' or 'serve' mode
apply: 'build', // apply can also be a function
config(config, { command }) {
console.log('here is the config hook');
},
configResolved(resolvedConfig) {
console.log('here is the configResolved hook');
},
configureServer(server) {
console.log('here is the configureServer hook');
},
transformIndexHtml(html) {
console.log('here is the transformIndexHtml hook');
},
}
}
Os hooks de função do plugin do Vite serão explicados em detalhes abaixo~
Neste ponto, nosso template básico está criado, mas vamos pensar agora: como devemos executar este plugin?
Então precisamos criar alguns exemplos para executar este código;
4. Criar o diretório examples
Criei três conjuntos de demos de projetos aqui. Você pode copiá-los diretamente. Não vou apresentá-los em detalhes aqui.
vite-react
vite-vue2
vite-vue3
Se seu plugin precisar executar mais demos, basta criar o projeto você mesmo;
Então precisamos configurar o projeto em examples para fazer uma depuração conjunta com o plugin no diretório raiz atual (tomando examples/vite-vue3 como exemplo abaixo).
5. Configurar o projeto examples/vite-vue3
Modificar examples/vite-vue3/package.json
{
...
"devDependencies": {
...
"vite": "link:../../node_modules/vite",
"vite-plugin-template": "link:../../"
}
}
O acima significa:
Tornar a versão do Vite no projeto examples/vite-vue3 consistente com a versão no diretório raiz vite-plugin-template;
Ao mesmo tempo, apontar o vite-plugin-template no projeto examples/vite-vue3 para o plugin desenvolvido no diretório raiz atual;
Introduzir o plugin: examples/vite-vue3/vite.config.ts
import template from 'vite-plugin-template';
export default defineConfig({
...
plugins: [vue(), template()],
...
});
Instalar: cd examples/vite-vue3 && pnpm install
cd examples/vite-vue3 && pnpm install
Nota: a configuração de examples/vite-vue2 e examples/vite-react é consistente com esta
reflexão:
Neste ponto, vamos pensar novamente. Configuramos o projeto em examples/vite-vue3, mas como devemos executá-lo?
Ir diretamente ao diretório examples/vite-vue3 e executar pnpm run build ou pnpm run dev?
Obviamente isso não funcionará, porque o src/index.ts no nosso diretório raiz não pode ser executado diretamente, então precisamos converter o arquivo .ts em um arquivo .js;
Então, como lidamos com isso?
Então temos que tentar usar uma ferramenta pequena e sem configuração: tsup.
6. Instalar tsup e configurar comando de execução
tsup é uma ferramenta de build leve e sem configuração, suportada pelo esbuild;
Ao mesmo tempo, pode converter diretamente .ts, .tsx em ferramentas de diferentes formatos: esm, cjs, iife;
instalar tsup
pnpm i tsup -D
Configurado no package.json no diretório raiz
{
...
"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. Execução no ambiente de desenvolvimento
Operação no ambiente de desenvolvimento: monitoramento em tempo real de modificações de arquivos e reempacotamento (hot reload)
pnpm run dev
Executar qualquer projeto em examples (tomando vite-vue3 como exemplo)
pnpm run example:vue3
Aviso:
Se seu plugin só será executado no momento do build, defina "example:vue3": "cd examples/vite-vue3 && pnpm run build";
Caso contrário, execute pnpm run dev
saída:
A partir daqui, você pode executar enquanto desenvolve. A Yuxi disse que achou legal quando viu~
8. Publicar
Instalar bumpp para adicionar controle de versão e tags
pnpm i bumpp -D
configurar package.json
{
...
"scripts": {
...
"prepublishOnly": "pnpm run build",
"release": "npx bumpp --push --tag --commit && pnpm publish",
},
...
}
Executar publicação após desenvolver o plugin
# first step
pnpm run prepublishOnly
# second step
pnpm run release
Pronto, nosso template de plugin do Vite foi escrito. Você pode clonar diretamente o template vite-plugin-template para usar;
Se você tem interesse nos hooks de plugin do Vite e em implementar um plugin real do Vite, pode continuar lendo abaixo;
Hooks de plugin do Vite
1. Hooks exclusivos do Vite
enforce: o valor pode ser pre ou post, pre será executado antes de post;
apply: o valor pode ser build ou serve ou uma função, especificando que são chamados apenas no modo build ou serve;
config(config, env): Você pode modificar a configuração relacionada ao Vite antes de ele ser analisado. O hook recebe a configuração original do usuário config e uma variável env descrevendo o ambiente de configuração;
configResolved(resolvedConfig): Chamado após a configuração do Vite ser resolvida. Use este hook para ler e armazenar a configuração final resolvida. É útil quando um plugin precisa fazer algo diferente dependendo do comando executado.
configureServer(server): usado principalmente para configurar o servidor de desenvolvimento e adicionar middleware personalizado ao dev-server (aplicação connect);
transformIndexHtml(html): Hook dedicado para transformar index.html. O hook recebe a string HTML atual e o contexto de conversão;
handleHotUpdate(ctx): Executar atualização HMR personalizada, você pode enviar eventos personalizados ao cliente através de ws;
2. Fase de construção de hooks comuns do Vite e rollup
options(options): chamado quando o servidor inicia: obter e manipular as opções do Rollup; estritamente falando, é executado antes da fase de build;
buildStart(options): chamado toda vez que um build inicia;
resolveId(source, importer, options): chamado para cada solicitação de módulo recebida, cria uma função de confirmação personalizada, que pode ser usada para localizar dependências de terceiros;
load(id): Chamado para cada solicitação de módulo recebida, o loader pode ser personalizado e pode ser usado para retornar conteúdo personalizado;
transform(code, id): chamado para cada solicitação de módulo recebida, usado principalmente para transformar um único módulo;
buildEnd(): Chamado após o fim da fase de build, onde o fim do build significa apenas que todos os módulos foram convertidos;
3. Fase de saída dos hooks gerais do Vite e rollup
outputOptions(options): aceita parâmetros de saída;
renderStart(outputOptions, inputOptions): será disparado toda vez que bundle.generate e bundle.write forem chamados;
augmentChunkHash(chunkInfo): usado para adicionar hash ao chunk;
renderChunk(code, chunk, options): Disparado quando um único chunk é traduzido. O rollup é chamado quando cada arquivo chunk é gerado;
generateBundle(options, bundle, isWrite): dispara este hook imediatamente antes de chamar bundle.write;
writeBundle(options, bundle): Após chamar bundle.write, depois que todos os chunks forem escritos no arquivo, writeBundle será chamado no final;
closeBundle(): chamado quando o servidor é fechado
4. Ordem de execução dos hooks de função do plugin (conforme mostrado abaixo)
5. Ordem de execução dos plugins
Tratamento de Alias
Plugin do usuário com enforce: 'pre'
Plugin principal do Vite
Plugin do usuário sem enforce definido
Plugin de build do Vite
Plugin do usuário com enforce: 'post'
Plugins pós-build do Vite (minify, manifest, relatórios)
Criar um plugin do Vite na prática
A seguir, tomamos o plugin de barra de progresso de empacotamento do Vite como exemplo;
Endereço do plugin: GitHub. Se gostar, fique à vontade para dar uma estrela ⭐️
O plugin foi oficialmente incluído pelo Vite na documentação oficial: link
Como o foco deste artigo não é o processo detalhado de implementação deste plugin, este artigo apenas colará o código-fonte para sua referência. A introdução detalhada será explicada no próximo artigo, aguarde!
index.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
type Merge
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,
...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');
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(' ');
stream.write(' ');
}
};
/**
* run cache data of progress
*/
function runCachedData() {
if (transformCount === 1) {
stream.write(' ');
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));
};
por fim
Esta série terá atualizações contínuas. Em relação a toda a coluna "Vite do Iniciante ao Domínio", explicarei principalmente pelos seguintes aspectos, aguarde!!!
Pessoal, vocês viram tudo até aqui, por que não curtiram 👍.markdown-body pre,.markdown-body pre>code.hljs{color:#333;background:#f8f8f8}.hljs-comment,.hljs-quote{color:#998;font-style:italic}.hljs-keyword,.hljs-selector-tag,.hljs-subst{color:#333;font-weight:700}.hljs-literal,.hljs-number,.hljs-tag .hljs-attr,.hljs-template-variable,.hljs-variable{color:teal}.hljs-doctag,.hljs-string{color:#d14}.hljs-section,.hljs-selector-id,.hljs-title{color:#900;font-weight:700}.hljs-subst{font-weight:400}.hljs-class .hljs-title,.hljs-type{color:#458;font-weight:700}.hljs-attribute,.hljs-name,.hljs-tag{color:navy;font-weight:400}.hljs-link,.hljs-regexp{color:#009926}.hljs-bullet,.hljs-symbol{color:#990073}.hljs-built_in,.hljs-builtin-name{color:#0086b3}.hljs-meta{color:#999;font-weight:700}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700} Categoria: Front-end Tags: Front-end Vite Artigos incluídos na coluna:
Vite do início ao domínio
Vite (pronunciado de forma semelhante a [weɪt], leve, significado de leveza) é uma ferramenta de build front-end para desenvolvimento web impulsionada por ES Module nativo.
Possui as seguintes características:
💡 Início de serviço extremamente rápido;
⚡️ Hot reload leve e rápido;
🛠️ Funções ricas;
📦 Build otimizado;
🔩 Plugin universal;
🔑 API totalmente tipada.
Artigos relacionados
-
6 tecnologias opcionais para armazenamento de dados
Equipe da base de conhecimento
Explorar mais ofertas especiais
-
Short Message Service (SMS) e Serviço de e-mail
Pacote de 50.000 e-mails a partir de apenas USD 1,99; 120 mensagens curtas a partir de apenas USD 1,00
