vite-intlayer 8.3.0 → 8.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/IntlayerCompilerPlugin.mjs +1 -1
- package/dist/esm/IntlayerCompilerPlugin.mjs.map +1 -1
- package/dist/esm/intlayerOptimizePlugin.mjs +1 -1
- package/dist/esm/intlayerOptimizePlugin.mjs.map +1 -1
- package/dist/types/IntlayerCompilerPlugin.d.ts.map +1 -1
- package/dist/types/intlayerOptimizePlugin.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{readFile as e}from"node:fs/promises";import{dirname as t,relative as n}from"node:path";import{detectPackageName as r,extractContent as i,getExtractPluginOptions as a,writeContentHelper as o}from"@intlayer/babel";import{ANSIColors as s,colorize as c,colorizeKey as l,colorizeNumber as u,colorizePath as d,getAppLogger as f}from"@intlayer/config/logger";import{getConfiguration as
|
|
1
|
+
import{readFile as e}from"node:fs/promises";import{dirname as t,relative as n}from"node:path";import{detectPackageName as r,extractContent as i,getExtractPluginOptions as a,writeContentHelper as o}from"@intlayer/babel";import{ANSIColors as s,colorize as c,colorizeKey as l,colorizeNumber as u,colorizePath as d,getAppLogger as f,x as p}from"@intlayer/config/logger";import{getConfiguration as m}from"@intlayer/config/node";const h=h=>{let g,_,v,y=``,b=[],x=null,S=new Map,C=new Map,w=e=>{let t=S.get(e);return t?Date.now()-t<500:!1},T=e=>{S.set(e,Date.now());let t=Date.now();for(let[e,n]of S.entries())t-n>500*2&&S.delete(e)},E=e=>JSON.stringify(Object.keys(e).sort().map(t=>[t,e[t]])),D=(e,t)=>{let n=E(t);return C.get(e)===n?!1:(C.set(e,n),!0)},O=async()=>{b=_.filesList},k=async e=>{g=m(h?.configOptions),_=a(g,e),v=f(g),await O()},A=async e=>{let t=e.env?.DEV?`dev`:`build`;y=e.root,await k(t)},j=async()=>{try{v(`Intlayer compiler initialized`,{level:`info`})}catch(e){v(`${c(`Compiler:`,s.GREY_DARK)} Failed to prepare Intlayer: ${e}`,{level:`error`})}},M=async()=>{x&&await x},N=async({file:t,server:r,modules:i})=>{if(b.some(e=>e===t)){if(w(t)){v(`${c(`Compiler:`,s.GREY_DARK)} Skipping re-transform of ${d(n(y,t))} (recently processed)`,{level:`info`,isVerbose:!0});return}T(t);for(let e of i)r.moduleGraph.invalidateModule(e);try{await I(await e(t,`utf-8`),t)}catch(e){v(`${c(`Compiler:`,s.GREY_DARK)} Failed to re-transform ${t}: ${e}`,{level:`error`})}r.ws.send({type:`full-reload`})}},P=async e=>{let{dictionaryKey:t,content:n,filePath:r}=e;if(!D(t,n)){v(`${c(`Compiler:`,s.GREY_DARK)} Skipping dictionary ${l(t)} (content unchanged)`,{level:`info`,isVerbose:!0});return}try{await o(n,t,r,g)}catch(e){v(`${c(`Compiler:`,s.GREY_DARK)} Failed to write/build dictionary for ${l(t)}: ${e}`,{level:`error`})}},F=async e=>{let t=Object.keys(e.content);return v(`${c(`Compiler:`,s.GREY_DARK)} Extracted ${u(t.length)} content keys from ${d(n(y,e.filePath))}`,{level:`info`}),x=(x??Promise.resolve()).then(()=>P(e)).catch(e=>{v(`${c(`Compiler:`,s.GREY_DARK)} Error in dictionary write chain: ${e}`,{level:`error`})}),x},I=async(e,a)=>{if(!_.enabled||a.includes(`?`))return;let o=a;if(b.includes(o)){v(`${c(`Compiler:`,s.GREY_DARK)} Transforming ${d(n(y,o))}`,{level:`info`,isVerbose:!0});try{let n=await i(o,r(t(o)),{configuration:g,code:e,onExtract:async({key:e,content:t})=>{await F({dictionaryKey:e,content:t,filePath:o,locale:g.internationalization.defaultLocale})}});if(x&&await x,n?.transformedCode)return{code:n.transformedCode}}catch(e){v([`Failed to transform ${d(n(y,o))}:`,e],{level:`error`})}}};return{name:`vite-intlayer-compiler`,enforce:`pre`,configResolved:A,buildStart:j,buildEnd:M,handleHotUpdate:N,transform:I,apply:(e,t)=>(g||=m(h?.configOptions),v||=f(g),g.compiler.output?(_||=a(g,t.command),_.enabled):(v(`${p} No output configuration found. Add a ${c(`compiler.output`,s.BLUE)} in your configuration.`,{level:`error`}),!1))}};export{h as intlayerCompiler};
|
|
2
2
|
//# sourceMappingURL=IntlayerCompilerPlugin.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntlayerCompilerPlugin.mjs","names":[],"sources":["../../src/IntlayerCompilerPlugin.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, relative } from 'node:path';\nimport {\n type CompilerMode,\n detectPackageName,\n type ExtractPluginOptions,\n type ExtractResult,\n extractContent,\n getExtractPluginOptions,\n writeContentHelper,\n} from '@intlayer/babel';\nimport {\n ANSIColors,\n colorize,\n colorizeKey,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types/config';\nimport type { HmrContext, PluginOption } from 'vite';\n\n/**\n * Options for initializing the compiler\n */\nexport type IntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Create an IntlayerCompiler - A Vite-compatible compiler plugin for Intlayer\n *\n * This autonomous compiler handles:\n * - Configuration loading and management\n * - Hot Module Replacement (HMR) for content changes\n * - File transformation with content extraction\n * - Dictionary persistence and building\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { intlayerCompiler } from 'vite-intlayer';\n *\n * export default defineConfig({\n * plugins: [intlayerCompiler()],\n * });\n * ```\n */\nexport const intlayerCompiler = (\n options?: IntlayerCompilerOptions\n): PluginOption => {\n let config: IntlayerConfig;\n let compilerConfig: ExtractPluginOptions;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let filesList: string[] = [];\n\n // Promise to track dictionary writing (for synchronization)\n let pendingDictionaryWrite: Promise<void> | null = null;\n\n // Track recently processed files to prevent infinite loops\n // Key: file path, Value: timestamp of last processing\n const recentlyProcessedFiles = new Map<string, number>();\n // Track recently written dictionaries to prevent duplicate writes\n // Key: dictionary key, Value: hash of content that was written\n const recentDictionaryContent = new Map<string, string>();\n // Debounce window in milliseconds - skip re-processing files within this window\n const DEBOUNCE_MS = 500;\n\n /**\n * Check if a file was recently processed (within debounce window)\n * and should be skipped to prevent infinite loops\n */\n const wasRecentlyProcessed = (filePath: string): boolean => {\n const lastProcessed = recentlyProcessedFiles.get(filePath);\n if (!lastProcessed) return false;\n\n const now = Date.now();\n return now - lastProcessed < DEBOUNCE_MS;\n };\n\n /**\n * Mark a file as recently processed\n */\n const markAsProcessed = (filePath: string): void => {\n recentlyProcessedFiles.set(filePath, Date.now());\n\n // Clean up old entries to prevent memory leaks\n const now = Date.now();\n for (const [path, timestamp] of recentlyProcessedFiles.entries()) {\n if (now - timestamp > DEBOUNCE_MS * 2) {\n recentlyProcessedFiles.delete(path);\n }\n }\n };\n\n /**\n * Create a simple hash of content for comparison\n * Used to detect if dictionary content has actually changed\n */\n const hashContent = (content: Record<string, string>): string =>\n JSON.stringify(\n Object.keys(content)\n .sort()\n .map((key) => [key, content[key]])\n );\n\n /**\n * Check if dictionary content has changed since last write\n */\n const hasDictionaryContentChanged = (\n dictionaryKey: string,\n content: Record<string, string>\n ): boolean => {\n const newHash = hashContent(content);\n const previousHash = recentDictionaryContent.get(dictionaryKey);\n\n if (previousHash === newHash) {\n return false;\n }\n\n // Update the stored hash\n recentDictionaryContent.set(dictionaryKey, newHash);\n return true;\n };\n\n /**\n * Build the list of files to transform based on configuration patterns\n */\n const buildFilesListFn = async (): Promise<void> => {\n filesList = compilerConfig.filesList;\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n config = getConfiguration(options?.configOptions);\n\n compilerConfig = getExtractPluginOptions(config, compilerMode);\n\n logger = getAppLogger(config);\n\n // Build files list for transformation\n await buildFilesListFn();\n };\n\n /**\n * Vite hook: configResolved\n * Called when Vite config is resolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n\n await init(compilerMode);\n };\n\n /**\n * Build start hook - no longer needs to prepare dictionaries\n * The compiler is now autonomous and extracts content inline\n */\n const buildStart = async (): Promise<void> => {\n // Bootstrap dictionaries and types before build starts\n // This ensures existing dictionaries are available for resolution\n try {\n logger('Intlayer compiler initialized', {\n level: 'info',\n });\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to prepare Intlayer: ${error}`,\n {\n level: 'error',\n }\n );\n }\n };\n\n /**\n * Build end hook - wait for any pending dictionary writes\n */\n const buildEnd = async (): Promise<void> => {\n // Wait for any pending dictionary writes to complete\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\n }\n };\n\n /**\n * Vite hook: handleHotUpdate\n * Handles HMR for content files - invalidates cache and triggers re-transform\n */\n const handleHotUpdate = async ({\n file,\n server,\n modules,\n }: HmrContext): Promise<void> => {\n // Check if this is a file we should transform\n const isTransformableFile = filesList.some((fileEl) => fileEl === file);\n\n if (isTransformableFile) {\n // Check if this file was recently processed to prevent infinite loops\n // When a component is transformed, it writes a dictionary, which triggers HMR,\n // which would re-transform the component - this debounce prevents that loop\n if (wasRecentlyProcessed(file)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping re-transform of ${colorizePath(relative(projectRoot, file))} (recently processed)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return undefined;\n }\n\n // Mark file as being processed before transformation\n markAsProcessed(file);\n\n // Invalidate all affected modules to ensure re-transform\n for (const mod of modules) {\n server.moduleGraph.invalidateModule(mod);\n }\n\n // Force re-transform by reading and processing the file\n // This ensures content extraction happens on every file change\n try {\n const code = await readFile(file, 'utf-8');\n\n // Trigger the transform manually to extract content\n await transformHandler(code, file);\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to re-transform ${file}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n // Trigger full reload for content changes\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n /**\n * Write and build one or more dictionaries based on extracted content.\n * Leverages shared logic from @intlayer/babel.\n */\n const writeAndBuildDictionary = async (\n result: ExtractResult\n ): Promise<void> => {\n const { dictionaryKey, content, filePath: sourceFilePath } = result;\n\n // Skip if content hasn't changed - prevents infinite loops during HMR\n if (!hasDictionaryContentChanged(dictionaryKey, content)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping dictionary ${colorizeKey(dictionaryKey)} (content unchanged)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return;\n }\n\n try {\n await writeContentHelper(content, dictionaryKey, sourceFilePath!, config);\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to write/build dictionary for ${colorizeKey(dictionaryKey)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n };\n\n /**\n * Callback for when content is extracted from a file\n * Immediately writes and builds the dictionary\n */\n const handleExtractedContent = async (\n result: ExtractResult\n ): Promise<void> => {\n const contentKeys = Object.keys(result.content);\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted ${colorizeNumber(contentKeys.length)} content keys from ${colorizePath(relative(projectRoot, result.filePath))}`,\n {\n level: 'info',\n }\n );\n\n // Chain the write operation to ensure sequential writes\n pendingDictionaryWrite = (pendingDictionaryWrite ?? Promise.resolve())\n .then(() => writeAndBuildDictionary(result))\n .catch((error) => {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Error in dictionary write chain: ${error}`,\n {\n level: 'error',\n }\n );\n });\n\n return pendingDictionaryWrite;\n };\n\n /**\n * Transform a file using the appropriate extraction plugin based on file type.\n * Delegates to `extractContent` from `@intlayer/babel` which handles\n * JS/TS/JSX/TSX/Vue/Svelte extraction and transformation.\n */\n const transformHandler = async (code: string, id: string) => {\n // Only transform if compiler is enabled\n if (!compilerConfig.enabled) {\n return undefined;\n }\n\n // Skip virtual modules (query strings indicate compiled/virtual modules)\n // e.g., App.svelte?svelte&type=style, Component.vue?vue&type=script\n if (id.includes('?')) {\n return undefined;\n }\n\n const filename = id;\n\n if (!filesList.includes(filename)) {\n return undefined;\n }\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transforming ${colorizePath(relative(projectRoot, filename))}`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n\n try {\n const packageName = detectPackageName(dirname(filename));\n\n const result = await extractContent(filename, packageName, {\n configuration: config,\n code,\n // Dictionary writing is handled by handleExtractedContent below.\n onExtract: async ({ key, content }) => {\n await handleExtractedContent({\n dictionaryKey: key,\n content,\n filePath: filename,\n locale: config.internationalization.defaultLocale,\n });\n },\n });\n\n // Wait for the dictionary to be written before returning\n // This ensures the dictionary exists before any subsequent processing\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\n }\n\n if (result?.transformedCode) {\n return {\n code: result.transformedCode,\n };\n }\n } catch (error) {\n logger(\n [\n `Failed to transform ${colorizePath(relative(projectRoot, filename))}:`,\n error,\n ],\n {\n level: 'error',\n }\n );\n }\n\n return undefined;\n };\n\n return {\n name: 'vite-intlayer-compiler',\n enforce: 'pre',\n configResolved,\n buildStart,\n buildEnd,\n handleHotUpdate,\n transform: transformHandler,\n apply: (_viteConfig, env) => {\n // Initialize config if not already done\n if (!config) {\n config = getConfiguration(options?.configOptions);\n }\n if (!logger) {\n logger = getAppLogger(config);\n }\n\n if (!compilerConfig) {\n compilerConfig = getExtractPluginOptions(config, env.command);\n }\n\n return compilerConfig.enabled;\n },\n };\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"IntlayerCompilerPlugin.mjs","names":[],"sources":["../../src/IntlayerCompilerPlugin.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { dirname, relative } from 'node:path';\nimport {\n type CompilerMode,\n detectPackageName,\n type ExtractPluginOptions,\n type ExtractResult,\n extractContent,\n getExtractPluginOptions,\n writeContentHelper,\n} from '@intlayer/babel';\nimport {\n ANSIColors,\n colorize,\n colorizeKey,\n colorizeNumber,\n colorizePath,\n getAppLogger,\n x,\n} from '@intlayer/config/logger';\nimport {\n type GetConfigurationOptions,\n getConfiguration,\n} from '@intlayer/config/node';\nimport type { CompilerConfig, IntlayerConfig } from '@intlayer/types/config';\nimport type { HmrContext, PluginOption } from 'vite';\n\n/**\n * Options for initializing the compiler\n */\nexport type IntlayerCompilerOptions = {\n /**\n * Configuration options for getting the intlayer configuration\n */\n configOptions?: GetConfigurationOptions;\n\n /**\n * Custom compiler configuration to override defaults\n */\n compilerConfig?: Partial<CompilerConfig>;\n};\n\n/**\n * Create an IntlayerCompiler - A Vite-compatible compiler plugin for Intlayer\n *\n * This autonomous compiler handles:\n * - Configuration loading and management\n * - Hot Module Replacement (HMR) for content changes\n * - File transformation with content extraction\n * - Dictionary persistence and building\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite';\n * import { intlayerCompiler } from 'vite-intlayer';\n *\n * export default defineConfig({\n * plugins: [intlayerCompiler()],\n * });\n * ```\n */\nexport const intlayerCompiler = (\n options?: IntlayerCompilerOptions\n): PluginOption => {\n let config: IntlayerConfig;\n let compilerConfig: ExtractPluginOptions;\n let logger: ReturnType<typeof getAppLogger>;\n let projectRoot = '';\n let filesList: string[] = [];\n\n // Promise to track dictionary writing (for synchronization)\n let pendingDictionaryWrite: Promise<void> | null = null;\n\n // Track recently processed files to prevent infinite loops\n // Key: file path, Value: timestamp of last processing\n const recentlyProcessedFiles = new Map<string, number>();\n // Track recently written dictionaries to prevent duplicate writes\n // Key: dictionary key, Value: hash of content that was written\n const recentDictionaryContent = new Map<string, string>();\n // Debounce window in milliseconds - skip re-processing files within this window\n const DEBOUNCE_MS = 500;\n\n /**\n * Check if a file was recently processed (within debounce window)\n * and should be skipped to prevent infinite loops\n */\n const wasRecentlyProcessed = (filePath: string): boolean => {\n const lastProcessed = recentlyProcessedFiles.get(filePath);\n if (!lastProcessed) return false;\n\n const now = Date.now();\n return now - lastProcessed < DEBOUNCE_MS;\n };\n\n /**\n * Mark a file as recently processed\n */\n const markAsProcessed = (filePath: string): void => {\n recentlyProcessedFiles.set(filePath, Date.now());\n\n // Clean up old entries to prevent memory leaks\n const now = Date.now();\n for (const [path, timestamp] of recentlyProcessedFiles.entries()) {\n if (now - timestamp > DEBOUNCE_MS * 2) {\n recentlyProcessedFiles.delete(path);\n }\n }\n };\n\n /**\n * Create a simple hash of content for comparison\n * Used to detect if dictionary content has actually changed\n */\n const hashContent = (content: Record<string, string>): string =>\n JSON.stringify(\n Object.keys(content)\n .sort()\n .map((key) => [key, content[key]])\n );\n\n /**\n * Check if dictionary content has changed since last write\n */\n const hasDictionaryContentChanged = (\n dictionaryKey: string,\n content: Record<string, string>\n ): boolean => {\n const newHash = hashContent(content);\n const previousHash = recentDictionaryContent.get(dictionaryKey);\n\n if (previousHash === newHash) {\n return false;\n }\n\n // Update the stored hash\n recentDictionaryContent.set(dictionaryKey, newHash);\n return true;\n };\n\n /**\n * Build the list of files to transform based on configuration patterns\n */\n const buildFilesListFn = async (): Promise<void> => {\n filesList = compilerConfig.filesList;\n };\n\n /**\n * Initialize the compiler with the given mode\n */\n const init = async (compilerMode: CompilerMode): Promise<void> => {\n config = getConfiguration(options?.configOptions);\n\n compilerConfig = getExtractPluginOptions(config, compilerMode);\n\n logger = getAppLogger(config);\n\n // Build files list for transformation\n await buildFilesListFn();\n };\n\n /**\n * Vite hook: configResolved\n * Called when Vite config is resolved\n */\n const configResolved = async (viteConfig: {\n env?: { DEV?: boolean };\n root: string;\n }): Promise<void> => {\n const compilerMode: CompilerMode = viteConfig.env?.DEV ? 'dev' : 'build';\n projectRoot = viteConfig.root;\n\n await init(compilerMode);\n };\n\n /**\n * Build start hook - no longer needs to prepare dictionaries\n * The compiler is now autonomous and extracts content inline\n */\n const buildStart = async (): Promise<void> => {\n // Bootstrap dictionaries and types before build starts\n // This ensures existing dictionaries are available for resolution\n try {\n logger('Intlayer compiler initialized', {\n level: 'info',\n });\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to prepare Intlayer: ${error}`,\n {\n level: 'error',\n }\n );\n }\n };\n\n /**\n * Build end hook - wait for any pending dictionary writes\n */\n const buildEnd = async (): Promise<void> => {\n // Wait for any pending dictionary writes to complete\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\n }\n };\n\n /**\n * Vite hook: handleHotUpdate\n * Handles HMR for content files - invalidates cache and triggers re-transform\n */\n const handleHotUpdate = async ({\n file,\n server,\n modules,\n }: HmrContext): Promise<void> => {\n // Check if this is a file we should transform\n const isTransformableFile = filesList.some((fileEl) => fileEl === file);\n\n if (isTransformableFile) {\n // Check if this file was recently processed to prevent infinite loops\n // When a component is transformed, it writes a dictionary, which triggers HMR,\n // which would re-transform the component - this debounce prevents that loop\n if (wasRecentlyProcessed(file)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping re-transform of ${colorizePath(relative(projectRoot, file))} (recently processed)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return undefined;\n }\n\n // Mark file as being processed before transformation\n markAsProcessed(file);\n\n // Invalidate all affected modules to ensure re-transform\n for (const mod of modules) {\n server.moduleGraph.invalidateModule(mod);\n }\n\n // Force re-transform by reading and processing the file\n // This ensures content extraction happens on every file change\n try {\n const code = await readFile(file, 'utf-8');\n\n // Trigger the transform manually to extract content\n await transformHandler(code, file);\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to re-transform ${file}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n\n // Trigger full reload for content changes\n server.ws.send({ type: 'full-reload' });\n }\n };\n\n /**\n * Write and build one or more dictionaries based on extracted content.\n * Leverages shared logic from @intlayer/babel.\n */\n const writeAndBuildDictionary = async (\n result: ExtractResult\n ): Promise<void> => {\n const { dictionaryKey, content, filePath: sourceFilePath } = result;\n\n // Skip if content hasn't changed - prevents infinite loops during HMR\n if (!hasDictionaryContentChanged(dictionaryKey, content)) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Skipping dictionary ${colorizeKey(dictionaryKey)} (content unchanged)`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n return;\n }\n\n try {\n await writeContentHelper(content, dictionaryKey, sourceFilePath!, config);\n } catch (error) {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Failed to write/build dictionary for ${colorizeKey(dictionaryKey)}: ${error}`,\n {\n level: 'error',\n }\n );\n }\n };\n\n /**\n * Callback for when content is extracted from a file\n * Immediately writes and builds the dictionary\n */\n const handleExtractedContent = async (\n result: ExtractResult\n ): Promise<void> => {\n const contentKeys = Object.keys(result.content);\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Extracted ${colorizeNumber(contentKeys.length)} content keys from ${colorizePath(relative(projectRoot, result.filePath))}`,\n {\n level: 'info',\n }\n );\n\n // Chain the write operation to ensure sequential writes\n pendingDictionaryWrite = (pendingDictionaryWrite ?? Promise.resolve())\n .then(() => writeAndBuildDictionary(result))\n .catch((error) => {\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Error in dictionary write chain: ${error}`,\n {\n level: 'error',\n }\n );\n });\n\n return pendingDictionaryWrite;\n };\n\n /**\n * Transform a file using the appropriate extraction plugin based on file type.\n * Delegates to `extractContent` from `@intlayer/babel` which handles\n * JS/TS/JSX/TSX/Vue/Svelte extraction and transformation.\n */\n const transformHandler = async (code: string, id: string) => {\n // Only transform if compiler is enabled\n if (!compilerConfig.enabled) {\n return undefined;\n }\n\n // Skip virtual modules (query strings indicate compiled/virtual modules)\n // e.g., App.svelte?svelte&type=style, Component.vue?vue&type=script\n if (id.includes('?')) {\n return undefined;\n }\n\n const filename = id;\n\n if (!filesList.includes(filename)) {\n return undefined;\n }\n\n logger(\n `${colorize('Compiler:', ANSIColors.GREY_DARK)} Transforming ${colorizePath(relative(projectRoot, filename))}`,\n {\n level: 'info',\n isVerbose: true,\n }\n );\n\n try {\n const packageName = detectPackageName(dirname(filename));\n\n const result = await extractContent(filename, packageName, {\n configuration: config,\n code,\n // Dictionary writing is handled by handleExtractedContent below.\n onExtract: async ({ key, content }) => {\n await handleExtractedContent({\n dictionaryKey: key,\n content,\n filePath: filename,\n locale: config.internationalization.defaultLocale,\n });\n },\n });\n\n // Wait for the dictionary to be written before returning\n // This ensures the dictionary exists before any subsequent processing\n if (pendingDictionaryWrite) {\n await pendingDictionaryWrite;\n }\n\n if (result?.transformedCode) {\n return {\n code: result.transformedCode,\n };\n }\n } catch (error) {\n logger(\n [\n `Failed to transform ${colorizePath(relative(projectRoot, filename))}:`,\n error,\n ],\n {\n level: 'error',\n }\n );\n }\n\n return undefined;\n };\n\n return {\n name: 'vite-intlayer-compiler',\n enforce: 'pre',\n configResolved,\n buildStart,\n buildEnd,\n handleHotUpdate,\n transform: transformHandler,\n apply: (_viteConfig, env) => {\n // Initialize config if not already done\n if (!config) {\n config = getConfiguration(options?.configOptions);\n }\n if (!logger) {\n logger = getAppLogger(config);\n }\n\n if (!config.compiler.output) {\n logger(\n `${x} No output configuration found. Add a ${colorize('compiler.output', ANSIColors.BLUE)} in your configuration.`,\n {\n level: 'error',\n }\n );\n\n return false;\n }\n\n if (!compilerConfig) {\n compilerConfig = getExtractPluginOptions(config, env.command);\n }\n\n return compilerConfig.enabled;\n },\n };\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{intlayerVueAsyncPlugin as e}from"./intlayerVueAsyncPlugin.mjs";import{join as t}from"node:path";import{intlayerOptimizeBabelPlugin as n}from"@intlayer/babel";import{getAppLogger as r}from"@intlayer/config/logger";import{transformSync as i}from"@babel/core";import{
|
|
1
|
+
import{intlayerVueAsyncPlugin as e}from"./intlayerVueAsyncPlugin.mjs";import{join as t}from"node:path";import{intlayerOptimizeBabelPlugin as n}from"@intlayer/babel";import{getAppLogger as r}from"@intlayer/config/logger";import{transformSync as i}from"@babel/core";import{buildComponentFilesList as a,runOnce as o}from"@intlayer/chokidar/utils";import{DefaultValues as s}from"@intlayer/config/client";import{getDictionaries as c}from"@intlayer/dictionaries-entry";const l=/\b(use|get)Intlayer\b/,u=async u=>{try{let d=r(u),{optimize:f}=u.build,p=u.build.importMode??u.dictionary?.importMode,{dictionariesDir:m,dynamicDictionariesDir:h,unmergedDictionariesDir:g,fetchDictionariesDir:_,mainDir:v}=u.system,{baseDir:y}=u.system,b=t(v,`dictionaries.mjs`),x=t(v,`unmerged_dictionaries.mjs`),S=t(v,`dynamic_dictionaries.mjs`),C=[...a(u),b,x],w=c(u),T={};return Object.values(w).forEach(e=>{T[e.key]=e.importMode??p??s.Dictionary.IMPORT_MODE}),[e(u,C),{name:`vite-intlayer-babel-transform`,enforce:`post`,apply:(e,n)=>{let r=n.command===`build`,i=f===void 0&&r||f===!0;return i&&o(t(y,`.intlayer`,`cache`,`intlayer-prune-plugin-enabled.lock`),()=>d(`Build optimization enabled`),{cacheTimeoutMs:1e3*10}),i},transform(e,t){let r=t.split(`?`,1)[0];if(!C.includes(r))return null;let a=[b,x].includes(r);if(!(l.test(e)||a))return null;let o=i(e,{filename:r,plugins:[[n,{optimize:f,dictionariesDir:m,dictionariesEntryPath:b,unmergedDictionariesEntryPath:x,unmergedDictionariesDir:g,dynamicDictionariesDir:h,dynamicDictionariesEntryPath:S,fetchDictionariesDir:_,importMode:p,filesList:C,replaceDictionaryEntry:!0,dictionaryModeMap:T}]],parserOpts:{sourceType:`module`,allowImportExportEverywhere:!0,plugins:[`typescript`,`jsx`,`decorators-legacy`,`classProperties`,`objectRestSpread`,`asyncGenerators`,`functionBind`,`exportDefaultFrom`,`exportNamespaceFrom`,`dynamicImport`,`nullishCoalescingOperator`,`optionalChaining`]}});if(o?.code)return{code:o.code,map:o.map}}}]}catch(e){return console.warn(`Failed to transform with Babel plugin:`,e),[]}};export{u as intlayerOptimize};
|
|
2
2
|
//# sourceMappingURL=intlayerOptimizePlugin.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerOptimizePlugin.mjs","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { transformSync } from '@babel/core';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport {
|
|
1
|
+
{"version":3,"file":"intlayerOptimizePlugin.mjs","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"sourcesContent":["import { join } from 'node:path';\nimport { transformSync } from '@babel/core';\nimport { intlayerOptimizeBabelPlugin } from '@intlayer/babel';\nimport { buildComponentFilesList, runOnce } from '@intlayer/chokidar/utils';\nimport { DefaultValues } from '@intlayer/config/client';\nimport { getAppLogger } from '@intlayer/config/logger';\nimport { getDictionaries } from '@intlayer/dictionaries-entry';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport type { Dictionary } from '@intlayer/types/dictionary';\nimport type { PluginOption } from 'vite';\nimport { intlayerVueAsyncPlugin } from './intlayerVueAsyncPlugin';\n\nconst INTLAYER_USAGE_REGEX = /\\b(use|get)Intlayer\\b/;\n\nexport const intlayerOptimize = async (\n intlayerConfig: IntlayerConfig\n): Promise<PluginOption[]> => {\n try {\n const logger = getAppLogger(intlayerConfig);\n\n const { optimize } = intlayerConfig.build;\n const importMode =\n intlayerConfig.build.importMode ?? intlayerConfig.dictionary?.importMode;\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n } = intlayerConfig.system;\n const { baseDir } = intlayerConfig.system;\n\n const dictionariesEntryPath = join(mainDir, 'dictionaries.mjs');\n const unmergedDictionariesEntryPath = join(\n mainDir,\n 'unmerged_dictionaries.mjs'\n );\n const dynamicDictionariesEntryPath = join(\n mainDir,\n 'dynamic_dictionaries.mjs'\n );\n\n const baseFilesList = buildComponentFilesList(intlayerConfig);\n\n const filesList = [\n ...baseFilesList,\n dictionariesEntryPath, // should add dictionariesEntryPath to replace it by a empty object if import made dynamic\n unmergedDictionariesEntryPath, // should add dictionariesEntryPath to replace it by a empty object if import made dynamic\n ];\n\n const dictionaries = getDictionaries(intlayerConfig);\n\n const dictionaryModeMap: Record<string, 'static' | 'dynamic' | 'fetch'> =\n {};\n\n (Object.values(dictionaries) as Dictionary[]).forEach((dictionary) => {\n dictionaryModeMap[dictionary.key] =\n dictionary.importMode ??\n importMode ??\n DefaultValues.Dictionary.IMPORT_MODE;\n });\n\n return [\n intlayerVueAsyncPlugin(intlayerConfig, filesList),\n {\n name: 'vite-intlayer-babel-transform',\n enforce: 'post', // Run after other transformations as vue\n apply: (_config, env) => {\n // Only apply babel plugin if optimize is enabled\n\n const isBuild = env.command === 'build';\n const isEnabled =\n (optimize === undefined && isBuild) || optimize === true;\n\n if (isEnabled) {\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-prune-plugin-enabled.lock'\n ),\n () => logger('Build optimization enabled'),\n {\n cacheTimeoutMs: 1000 * 10, // 10 seconds\n }\n );\n }\n\n return isEnabled;\n },\n transform(code, id) {\n /**\n * Transform file as\n * .../HelloWorld.vue?vue&type=script&setup=true&lang.ts\n * Into\n * .../HelloWorld.vue\n *\n * Prevention for virtual file\n */\n const filename = id.split('?', 1)[0];\n\n if (!filesList.includes(filename)) return null;\n\n const isDictionaryEntry = [\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ].includes(filename);\n\n const isUsingIntlayer = INTLAYER_USAGE_REGEX.test(code);\n\n const shouldTransform = isUsingIntlayer || isDictionaryEntry;\n\n if (!shouldTransform) return null;\n\n const result = transformSync(code, {\n filename,\n plugins: [\n [\n intlayerOptimizeBabelPlugin,\n {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n importMode,\n filesList,\n replaceDictionaryEntry: true,\n dictionaryModeMap,\n },\n ],\n ],\n parserOpts: {\n sourceType: 'module',\n allowImportExportEverywhere: true,\n plugins: [\n 'typescript',\n 'jsx',\n 'decorators-legacy',\n 'classProperties',\n 'objectRestSpread',\n 'asyncGenerators',\n 'functionBind',\n 'exportDefaultFrom',\n 'exportNamespaceFrom',\n 'dynamicImport',\n 'nullishCoalescingOperator',\n 'optionalChaining',\n ],\n },\n });\n\n if (result?.code) {\n return {\n code: result.code,\n map: result.map,\n };\n }\n },\n },\n ];\n } catch (error) {\n console.warn('Failed to transform with Babel plugin:', error);\n\n return [];\n }\n};\n"],"mappings":"+cAYA,MAAM,EAAuB,wBAEhB,EAAmB,KAC9B,IAC4B,CAC5B,GAAI,CACF,IAAM,EAAS,EAAa,EAAe,CAErC,CAAE,YAAa,EAAe,MAC9B,EACJ,EAAe,MAAM,YAAc,EAAe,YAAY,WAE1D,CACJ,kBACA,yBACA,0BACA,uBACA,WACE,EAAe,OACb,CAAE,WAAY,EAAe,OAE7B,EAAwB,EAAK,EAAS,mBAAmB,CACzD,EAAgC,EACpC,EACA,4BACD,CACK,EAA+B,EACnC,EACA,2BACD,CAIK,EAAY,CAChB,GAHoB,EAAwB,EAAe,CAI3D,EACA,EACD,CAEK,EAAe,EAAgB,EAAe,CAE9C,EACJ,EAAE,CASJ,OAPC,OAAO,OAAO,EAAa,CAAkB,QAAS,GAAe,CACpE,EAAkB,EAAW,KAC3B,EAAW,YACX,GACA,EAAc,WAAW,aAC3B,CAEK,CACL,EAAuB,EAAgB,EAAU,CACjD,CACE,KAAM,gCACN,QAAS,OACT,OAAQ,EAAS,IAAQ,CAGvB,IAAM,EAAU,EAAI,UAAY,QAC1B,EACH,IAAa,IAAA,IAAa,GAAY,IAAa,GAiBtD,OAfI,GACF,EACE,EACE,EACA,YACA,QACA,qCACD,KACK,EAAO,6BAA6B,CAC1C,CACE,eAAgB,IAAO,GACxB,CACF,CAGI,GAET,UAAU,EAAM,EAAI,CASlB,IAAM,EAAW,EAAG,MAAM,IAAK,EAAE,CAAC,GAElC,GAAI,CAAC,EAAU,SAAS,EAAS,CAAE,OAAO,KAE1C,IAAM,EAAoB,CACxB,EACA,EACD,CAAC,SAAS,EAAS,CAMpB,GAAI,EAJoB,EAAqB,KAAK,EAAK,EAEZ,GAErB,OAAO,KAE7B,IAAM,EAAS,EAAc,EAAM,CACjC,WACA,QAAS,CACP,CACE,EACA,CACE,WACA,kBACA,wBACA,gCACA,0BACA,yBACA,+BACA,uBACA,aACA,YACA,uBAAwB,GACxB,oBACD,CACF,CACF,CACD,WAAY,CACV,WAAY,SACZ,4BAA6B,GAC7B,QAAS,CACP,aACA,MACA,oBACA,kBACA,mBACA,kBACA,eACA,oBACA,sBACA,gBACA,4BACA,mBACD,CACF,CACF,CAAC,CAEF,GAAI,GAAQ,KACV,MAAO,CACL,KAAM,EAAO,KACb,IAAK,EAAO,IACb,EAGN,CACF,OACM,EAAO,CAGd,OAFA,QAAQ,KAAK,yCAA0C,EAAM,CAEtD,EAAE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IntlayerCompilerPlugin.d.ts","names":[],"sources":["../../src/IntlayerCompilerPlugin.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"IntlayerCompilerPlugin.d.ts","names":[],"sources":["../../src/IntlayerCompilerPlugin.ts"],"mappings":";;;;;;;AA8BA;KAAY,uBAAA;;;;EAIV,aAAA,GAAgB,uBAAA;EAKQ;;;EAAxB,cAAA,GAAiB,OAAA,CAAQ,cAAA;AAAA;;;;;AAuB3B;;;;;;;;;;;;;;;;cAAa,gBAAA,GACX,OAAA,GAAU,uBAAA,KACT,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerOptimizePlugin.d.ts","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"intlayerOptimizePlugin.d.ts","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"mappings":";;;;cAca,gBAAA,GACX,cAAA,EAAgB,cAAA,KACf,OAAA,CAAQ,YAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-intlayer",
|
|
3
|
-
"version": "8.3.
|
|
3
|
+
"version": "8.3.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A Vite plugin for seamless internationalization (i18n), providing locale detection, redirection, and environment-based configuration",
|
|
6
6
|
"keywords": [
|
|
@@ -77,13 +77,13 @@
|
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
79
|
"@babel/core": "7.29.0",
|
|
80
|
-
"@intlayer/babel": "8.3.
|
|
81
|
-
"@intlayer/chokidar": "8.3.
|
|
82
|
-
"@intlayer/config": "8.3.
|
|
83
|
-
"@intlayer/core": "8.3.
|
|
84
|
-
"@intlayer/dictionaries-entry": "8.3.
|
|
85
|
-
"@intlayer/types": "8.3.
|
|
86
|
-
"intlayer": "8.3.
|
|
80
|
+
"@intlayer/babel": "8.3.1",
|
|
81
|
+
"@intlayer/chokidar": "8.3.1",
|
|
82
|
+
"@intlayer/config": "8.3.1",
|
|
83
|
+
"@intlayer/core": "8.3.1",
|
|
84
|
+
"@intlayer/dictionaries-entry": "8.3.1",
|
|
85
|
+
"@intlayer/types": "8.3.1",
|
|
86
|
+
"intlayer": "8.3.1"
|
|
87
87
|
},
|
|
88
88
|
"devDependencies": {
|
|
89
89
|
"@types/babel__core": "7.20.5",
|