vite面试题提交
This commit is contained in:
533
plugins/plugin-hooks.js
Normal file
533
plugins/plugin-hooks.js
Normal file
@@ -0,0 +1,533 @@
|
||||
/**
|
||||
* ============================================================
|
||||
* Rollup / Vite 插件钩子函数 完整参考手册
|
||||
* ============================================================
|
||||
*
|
||||
* 钩子分为两大阶段:
|
||||
* 1. Build 阶段 — 解析模块、构建依赖图
|
||||
* 2. Output Generate 阶段 — 生成最终产物(chunk/bundle)
|
||||
*
|
||||
* 钩子类型:
|
||||
* - async : 可返回 Promise,等待 resolve 后继续
|
||||
* - sync : 同步执行
|
||||
* - first : 多个插件有该钩子时,按顺序执行,第一个返回非 null 值的生效
|
||||
* - sequential : 多个插件按顺序依次执行
|
||||
* - parallel : 多个插件并行执行
|
||||
*
|
||||
* 以下是按 Rollup → Vite 分类的全部钩子。
|
||||
*/
|
||||
|
||||
// ============================================================
|
||||
// 一、Rollup 通用钩子(Build 阶段)
|
||||
// ============================================================
|
||||
|
||||
export default function pluginHooksDemo() {
|
||||
return {
|
||||
name: 'plugin-hooks-demo',
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 1. options
|
||||
// 类型: async, sequential
|
||||
// 触发时机: 读取完用户传入的 rollup/vite 配置后,开始构建之前
|
||||
// 用途: 替换或操纵传给 rollup 的 options 对象
|
||||
// ----------------------------------------------------------
|
||||
options(rawOptions) {
|
||||
// rawOptions — 用户的原始配置对象
|
||||
// 返回 null/undefined 不做修改
|
||||
// 返回一个 options 对象来覆盖(会合并到现有 options)
|
||||
console.log('[options] 原始配置:', Object.keys(rawOptions))
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 2. buildStart
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 构建开始时
|
||||
// 用途: 构建前的初始化、创建输出目录、注册构建级变量等
|
||||
// ----------------------------------------------------------
|
||||
buildStart(options) {
|
||||
// options — 最终合并后的配置对象
|
||||
console.log('[buildStart] 构建开始, input:', options.input)
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 3. resolveId
|
||||
// 类型: async, first
|
||||
// 触发时机: 解析模块导入路径时(对每个 import 都会调用)
|
||||
// 用途: 自定义模块解析逻辑,例如 alias、虚拟模块
|
||||
// ----------------------------------------------------------
|
||||
resolveId(source, importer, options) {
|
||||
// source — import 语句中的原始路径,如 './utils' 或 'vue'
|
||||
// importer — 发起导入的模块的绝对路径(入口模块为 undefined)
|
||||
// options — { attributes, custom, isEntry }
|
||||
//
|
||||
// 返回:
|
||||
// null — 交给下一个插件的 resolveId
|
||||
// string — 解析后的模块绝对路径
|
||||
// { id } — 对象形式,id 为解析路径
|
||||
// false — 标记为 external(不打包)
|
||||
console.log('[resolveId]', source, '←', importer)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 4. load
|
||||
// 类型: async, first
|
||||
// 触发时机: 加载模块源码内容时(resolveId 之后)
|
||||
// 用途: 返回模块内容,用于虚拟模块、加载非 JS 文件等
|
||||
// ----------------------------------------------------------
|
||||
load(id) {
|
||||
// id — 模块的绝对路径
|
||||
//
|
||||
// 返回:
|
||||
// null — 交给下一个插件
|
||||
// string — 模块源代码
|
||||
// { code, map, ... } — 带 sourcemap 等
|
||||
console.log('[load] 加载模块:', id)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 5. transform
|
||||
// 类型: async, sequential
|
||||
// 触发时机: 拿到模块源码后,AST 解析之前
|
||||
// 用途: 对单个模块源码做转换(最常见的钩子之一)
|
||||
// ----------------------------------------------------------
|
||||
transform(code, id) {
|
||||
// code — 模块源代码(前置插件 transform 后的结果)
|
||||
// id — 模块的绝对路径
|
||||
//
|
||||
// 返回:
|
||||
// null — 不做转换
|
||||
// string — 转换后的代码
|
||||
// { code, map, ... } — 带 sourcemap
|
||||
// { code, ast, ... } — 直接提供 AST(跳过解析)
|
||||
console.log('[transform] 转换模块:', id)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 6. moduleParsed
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 模块 AST 解析完成(所有 transform 之后)
|
||||
// 用途: 读取模块信息,如 import/export 列表
|
||||
// ----------------------------------------------------------
|
||||
moduleParsed(moduleInfo) {
|
||||
// moduleInfo 主要属性:
|
||||
// id — 模块路径
|
||||
// code — 模块源码
|
||||
// ast — ESTree 语法的 AST 树
|
||||
// importedIds — 静态 import 的模块 id 数组
|
||||
// dynamicallyImportedIds — 动态 import
|
||||
// importedIdResolutions — 静态 import 解析详情
|
||||
// dynamicallyImportedIdResolutions — 动态 import 解析详情
|
||||
// importers — 导入了本模块的模块 id 列表
|
||||
// dynamicImporters — 动态导入了本模块的模块 id 列表
|
||||
// isEntry — 是否为入口
|
||||
// isExternal — 是否为 external
|
||||
// meta — 插件间共享的自定义元数据对象
|
||||
// assertions/attributes — import assertions
|
||||
console.log('[moduleParsed] 解析完成:', moduleInfo.id)
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 7. resolveDynamicImport
|
||||
// 类型: async, first
|
||||
// 触发时机: 解析动态 import() 时
|
||||
// 用途: 自定义动态导入的解析逻辑
|
||||
// ----------------------------------------------------------
|
||||
resolveDynamicImport(specifier, importer) {
|
||||
// specifier — import(xxx) 中的 xxx
|
||||
// importer — 发起动态导入的模块路径
|
||||
//
|
||||
// 返回:
|
||||
// null — 交给下一个插件
|
||||
// { id, external }
|
||||
console.log('[resolveDynamicImport]', specifier, '←', importer)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 8. buildEnd
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 构建结束(无论成功/失败)时
|
||||
// 用途: 清理资源、关闭文件句柄、输出统计信息
|
||||
// ----------------------------------------------------------
|
||||
buildEnd(error) {
|
||||
// error — 如果构建失败则传入 Error 对象,成功则为 null
|
||||
if (error) {
|
||||
console.log('[buildEnd] 构建失败:', error.message)
|
||||
} else {
|
||||
console.log('[buildEnd] 构建结束')
|
||||
}
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 9. watchChange [Rollup watch 模式]
|
||||
// 类型: sync, sequential
|
||||
// 触发时机: rollup --watch 时文件发生变化
|
||||
// 用途: 监控文件变化,根据变更决定是否重新构建
|
||||
// ----------------------------------------------------------
|
||||
watchChange(id, change) {
|
||||
// id — 变化文件的绝对路径
|
||||
// change — { event: 'create' | 'update' | 'delete' }
|
||||
console.log('[watchChange]', change.event, ':', id)
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 10. closeWatcher [Rollup watch 模式]
|
||||
// 类型: async, parallel
|
||||
// 触发时机: watch 进程关闭时
|
||||
// 用途: 清理 watcher 相关资源
|
||||
// ----------------------------------------------------------
|
||||
closeWatcher() {
|
||||
console.log('[closeWatcher] watcher 关闭')
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// 二、Rollup Output Generation 阶段钩子
|
||||
// ============================================================
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 11. outputOptions
|
||||
// 类型: sync, sequential
|
||||
// 触发时机: 获取 outputOptions 时
|
||||
// 用途: 替换或操纵输出选项
|
||||
// ----------------------------------------------------------
|
||||
outputOptions(outputOptions) {
|
||||
// outputOptions — 输出配置对象
|
||||
console.log('[outputOptions] 输出配置:', Object.keys(outputOptions))
|
||||
return null // 返回新对象则替换
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 12. renderStart
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 每次调用 bundle.generate() 或 bundle.write() 时
|
||||
// 用途: 输出阶段的初始化
|
||||
// ----------------------------------------------------------
|
||||
renderStart(outputOptions, inputOptions) {
|
||||
console.log('[renderStart] 开始生成产物')
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 13. banner
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 每个 chunk 生成前
|
||||
// 用途: 在 chunk 最前面插入内容(如版权声明)
|
||||
// ----------------------------------------------------------
|
||||
banner(chunk) {
|
||||
// chunk — 当前 chunk 信息对象
|
||||
// 返回 string 或 Promise<string>
|
||||
// console.log('[banner] chunk:', chunk.fileName)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 14. footer
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 每个 chunk 生成前
|
||||
// 用途: 在 chunk 最后面追加内容
|
||||
// ----------------------------------------------------------
|
||||
footer(chunk) {
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 15. intro
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 每个 chunk 生成前
|
||||
// 用途: 在模块打包代码最前面插入内容(banner 之后、wrapper 内部)
|
||||
// ----------------------------------------------------------
|
||||
intro(chunk) {
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 16. outro
|
||||
// 类型: async, parallel
|
||||
// 触发时机: 每个 chunk 生成前
|
||||
// 用途: 在模块打包代码最后面追加内容(footer 之前、wrapper 内部)
|
||||
// ----------------------------------------------------------
|
||||
outro(chunk) {
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 17. renderChunk
|
||||
// 类型: async, sequential
|
||||
// 触发时机: 每个 chunk 的代码生成时
|
||||
// 用途: 对 chunk 代码做最终转换(可返回 sourcemap)
|
||||
// ----------------------------------------------------------
|
||||
renderChunk(code, chunk, outputOptions) {
|
||||
// code — chunk 的完整代码
|
||||
// chunk — chunk 信息对象
|
||||
// outputOptions — 输出配置
|
||||
//
|
||||
// 返回:
|
||||
// null — 不修改
|
||||
// string — 修改后代码
|
||||
// { code, map }
|
||||
console.log('[renderChunk]', chunk.fileName)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 18. augmentChunkHash
|
||||
// 类型: sync, sequential
|
||||
// 触发时机: 计算 chunk hash 时,用于追加自定义信息
|
||||
// 用途: 让 chunk hash 也能反映插件自定义内容的变化
|
||||
// ----------------------------------------------------------
|
||||
augmentChunkHash(chunkInfo) {
|
||||
// 返回一个字符串,会被追加到 hash 输入中
|
||||
// 常用于:[hash] 文件名需要反映插件版本等场景
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 19. renderDynamicImport
|
||||
// 类型: sync, first
|
||||
// 触发时机: 渲染动态 import 表达式时
|
||||
// 用途: 自定义动态 import 的运行时行为
|
||||
// ----------------------------------------------------------
|
||||
renderDynamicImport({ format, moduleId, targetModuleId, customResolution }) {
|
||||
// format — 输出格式 (es / cjs / …)
|
||||
// moduleId — 发起导入的模块 id
|
||||
// targetModuleId — 被导入模块 id
|
||||
// customResolution — resolveDynamicImport 返回的 custom 值
|
||||
//
|
||||
// 返回:
|
||||
// null — 默认渲染
|
||||
// { left, right } — 自定义 import 表达式的左/右半部分
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 20. resolveFileUrl
|
||||
// 类型: sync, first
|
||||
// 触发时机: 渲染文件引用 URL 时(如 import.meta.ROLLUP_FILE_URL_reference_xxx)
|
||||
// 用途: 自定义文件 URL 解析
|
||||
// ----------------------------------------------------------
|
||||
resolveFileUrl({ chunkId, fileName, format, moduleId, referenceId, relativePath }) {
|
||||
// 返回 null 使用默认,或返回自定义 URL 字符串
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 21. resolveImportMeta
|
||||
// 类型: sync, first
|
||||
// 触发时机: 渲染 import.meta 属性时
|
||||
// 用途: 自定义 import.meta.xxx 的展开逻辑
|
||||
// ----------------------------------------------------------
|
||||
resolveImportMeta(property, { chunkId, moduleId, format }) {
|
||||
// property — 访问的属性名,如 'url'
|
||||
// 返回:
|
||||
// null — 交给下一个插件
|
||||
// string — 替换为指定字符串
|
||||
// false — 保持 import.meta.property 不变
|
||||
console.log('[resolveImportMeta]', property, 'in', moduleId)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 22. generateBundle
|
||||
// 类型: async, sequential
|
||||
// 触发时机: bundle 生成完毕、写入磁盘之前
|
||||
// 用途: 增、删、改最终产物(最常用的输出钩子之一)
|
||||
// ----------------------------------------------------------
|
||||
generateBundle(options, bundle, isWrite) {
|
||||
// options — 输出配置
|
||||
// bundle — { [fileName]: AssetInfo | ChunkInfo }
|
||||
// isWrite — bundle.write() 为 true, bundle.generate() 为 false
|
||||
//
|
||||
// AssetInfo: { type: 'asset', fileName, source, name, needsCodeReference, ... }
|
||||
// ChunkInfo: { type: 'chunk', fileName, code, map, modules, exports, facadeModuleId, isEntry, ... }
|
||||
console.log('[generateBundle] 产物数:', Object.keys(bundle).length)
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 23. writeBundle
|
||||
// 类型: async, parallel
|
||||
// 触发时机: bundle 写入磁盘后
|
||||
// 用途: 产物写盘后的后处理(上传 CDN、生成报告等)
|
||||
// ----------------------------------------------------------
|
||||
writeBundle(options, bundle) {
|
||||
console.log('[writeBundle] 产物已写入磁盘')
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 24. closeBundle
|
||||
// 类型: async, parallel
|
||||
// 触发时机: bundle 生成完成后(最后的清理钩子)
|
||||
// 用途: 收尾清理
|
||||
// ----------------------------------------------------------
|
||||
closeBundle() {
|
||||
console.log('[closeBundle] Bundle 流程结束,清理资源')
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// 三、Vite 独有钩子
|
||||
// ============================================================
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 25. config
|
||||
// 类型: async, sequential
|
||||
// 触发时机: 解析 Vite 用户配置之前
|
||||
// 用途: 修改/扩展用户配置,或返回部分配置与已有配置合并
|
||||
// 这是 Vite 插件最常用的入口钩子
|
||||
// ----------------------------------------------------------
|
||||
config(config, env) {
|
||||
// config — 用户传入的 vite 配置(未解析)
|
||||
// env — { mode: 'development'|'production', command: 'serve'|'build', ssrBuild }
|
||||
//
|
||||
// 返回 null 或 部分配置对象(会被 deep-merge 到用户配置)
|
||||
console.log('[config] 模式:', env.mode, '命令:', env.command)
|
||||
return null
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 26. configResolved
|
||||
// 类型: async, parallel
|
||||
// 触发时机: Vite 配置解析完毕后
|
||||
// 用途: 读取最终配置,做插件内部初始化(常在此缓存 resolvedConfig)
|
||||
// ----------------------------------------------------------
|
||||
configResolved(resolvedConfig) {
|
||||
// resolvedConfig — 完整解析后的 Vite 配置(只读参考)
|
||||
console.log('[configResolved] root:', resolvedConfig.root)
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 27. configureServer
|
||||
// 类型: async, sequential
|
||||
// 触发时机: Vite 开发服务器创建时
|
||||
// 用途: 注册自定义中间件、WebSocket 事件等
|
||||
// ----------------------------------------------------------
|
||||
configureServer(viteDevServer) {
|
||||
// viteDevServer 主要属性/方法:
|
||||
// middlewares — Connect 实例,可用 .use() 添加中间件
|
||||
// httpServer — Node http.Server 实例
|
||||
// ws — WebSocket 服务器
|
||||
// watcher — chokidar 文件监听器
|
||||
// moduleGraph — 模块图
|
||||
// config — 最终配置
|
||||
// listen() — 启动服务器
|
||||
// close() — 关闭服务器
|
||||
// printUrls() — 打印服务地址
|
||||
// transformIndexHtml() — 转换 HTML
|
||||
// ssrFixStacktrace() — SSR 堆栈修复
|
||||
// ssrLoadModule() — SSR 加载模块
|
||||
// ssrTransform() — SSR 转换
|
||||
viteDevServer.middlewares.use((req, res, next) => {
|
||||
// 在这里可以拦截请求,自定义响应
|
||||
next()
|
||||
})
|
||||
console.log('[configureServer] 开发服务器已创建')
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 28. configurePreviewServer
|
||||
// 类型: async, sequential
|
||||
// 触发时机: vite preview 命令创建预览服务器时
|
||||
// 用途: 类似 configureServer,针对预览服务器
|
||||
// ----------------------------------------------------------
|
||||
configurePreviewServer(previewServer) {
|
||||
// previewServer 接口与 viteDevServer 类似
|
||||
previewServer.middlewares.use((req, res, next) => {
|
||||
next()
|
||||
})
|
||||
console.log('[configurePreviewServer] 预览服务器已创建')
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 29. transformIndexHtml
|
||||
// 类型: async, sequential / order: 'pre' | 'post' | undefined
|
||||
// 触发时机: 转换 index.html 时
|
||||
// 用途: 注入 <script> / <link> 标签、修改 HTML 内容
|
||||
// 这是 Vite 插件最常用的输出钩子之一
|
||||
// ----------------------------------------------------------
|
||||
transformIndexHtml: {
|
||||
// order: 'pre' — 在其他插件之前执行
|
||||
// order: 'post' — 在其他插件之后执行
|
||||
// 不设 order — 按插件注册顺序
|
||||
order: 'pre',
|
||||
handler(html, ctx) {
|
||||
// html — index.html 文本内容
|
||||
// ctx — 上下文对象
|
||||
// ctx.path — 请求路径
|
||||
// ctx.filename — HTML 文件路径
|
||||
// ctx.server — ViteDevServer 实例
|
||||
// ctx.bundle — 构建产物 bundle(serve 命令下可能为 undefined)
|
||||
// ctx.chunk — 当前 HTML 对应的 chunk
|
||||
// ctx.originalUrl — 原始请求 URL
|
||||
//
|
||||
// 返回:
|
||||
// string — 转换后的 HTML
|
||||
// { html: string, tags: [...] } — HTML + 注入标签
|
||||
// { tags: [...] } — 仅注入标签
|
||||
// Tag 格式:
|
||||
// { tag: 'script', attrs: { src: '/foo.js' }, injectTo: 'head'|'body'|'head-prepend'|'body-prepend' }
|
||||
// { tag: 'link', attrs: { rel: 'stylesheet', href: '/foo.css' }, injectTo: 'head' }
|
||||
// { tag: 'meta', attrs: { name: 'viewport', content: 'width=device-width' }, injectTo: 'head' }
|
||||
return html
|
||||
}
|
||||
},
|
||||
|
||||
// ----------------------------------------------------------
|
||||
// 30. handleHotUpdate
|
||||
// 类型: async, sequential / order: 'pre' | 'post' | undefined
|
||||
// 触发时机: HMR 热更新时文件变化
|
||||
// 用途: 自定义 HMR 更新行为:过滤哪些变更触发热更新、
|
||||
// 执行自定义 HMR 逻辑而非默认重载页面
|
||||
// ----------------------------------------------------------
|
||||
handleHotUpdate(ctx) {
|
||||
// ctx 上下文对象:
|
||||
// ctx.file — 变更的文件路径
|
||||
// ctx.modules — 受变更影响的模块数组
|
||||
// ctx.read() — 读取变更后文件内容
|
||||
// ctx.server — ViteDevServer 实例
|
||||
// ctx.timestamp — 变更时间戳
|
||||
//
|
||||
// 返回:
|
||||
// ModuleNode[] — 自定义受影响模块列表
|
||||
// void — 默认行为,使用 ctx.modules
|
||||
console.log('[handleHotUpdate] 文件变更:', ctx.file)
|
||||
},
|
||||
|
||||
// ============================================================
|
||||
// 四、已废弃的 Rollup 钩子(兼容旧插件,不推荐使用)
|
||||
// ============================================================
|
||||
|
||||
// transformBundle(code, options) → 请用 generateBundle 替代
|
||||
// transformChunk(code, options, chunk) → 请用 renderChunk 替代
|
||||
// ongenerate(options, bundle) → 请用 generateBundle 替代
|
||||
// onwrite(options, bundle) → 请用 writeBundle 替代
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 附:钩子执行顺序总览
|
||||
// ============================================================
|
||||
//
|
||||
// 【Build 阶段】
|
||||
// options → buildStart → (每个入口模块并行)
|
||||
// resolveId → load → transform → moduleParsed
|
||||
// → resolveDynamicImport(遇到动态 import 时)
|
||||
// → buildEnd
|
||||
//
|
||||
// 【Output Generate 阶段】
|
||||
// outputOptions → renderStart → (每个 chunk 顺序)
|
||||
// banner → footer → intro → outro
|
||||
// → renderChunk → augmentChunkHash
|
||||
// → renderDynamicImport → resolveFileUrl → resolveImportMeta
|
||||
// → generateBundle → writeBundle → closeBundle
|
||||
//
|
||||
// 【Watch 模式】
|
||||
// watchChange (文件变化时)
|
||||
// closeWatcher (退出时)
|
||||
//
|
||||
// 【Vite 独有】
|
||||
// config → configResolved
|
||||
// → configureServer → configurePreviewServer
|
||||
// → transformIndexHtml
|
||||
// → handleHotUpdate
|
||||
// ============================================================
|
||||
17
plugins/plugin-noconsole.js
Normal file
17
plugins/plugin-noconsole.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export default () => {
|
||||
return {
|
||||
name: 'helloPlugin',
|
||||
transform(src, id) {
|
||||
// 只处理 src 目录下的文件,跳过 node_modules
|
||||
if (!id.includes('/src/')) return null
|
||||
|
||||
// 生产环境:自动移除 console.log
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
const result = src.replace(/console\.log\([^)]*\);?/g, '')
|
||||
return {code: result, map: null}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user