vite-intlayer 8.7.8-canary.0 → 8.7.8
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.
|
@@ -257,7 +257,6 @@ const intlayerOptimize = async (intlayerConfig, pruneContext) => {
|
|
|
257
257
|
dictionaryModeMap: dictionaryKeyToImportModeMap
|
|
258
258
|
});
|
|
259
259
|
if (!transformResult) return null;
|
|
260
|
-
console.log({ code: transformResult.code });
|
|
261
260
|
return {
|
|
262
261
|
code: transformResult.code,
|
|
263
262
|
map: transformResult.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intlayerOptimizePlugin.mjs","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n analyzeFieldUsageInFile,\n buildNestedRenameMapFromContent,\n INTLAYER_USAGE_REGEX,\n optimizeSourceFile,\n type PruneContext,\n renameFieldsInSourceFile,\n SOURCE_FILE_REGEX,\n} from '@intlayer/babel';\nimport {\n buildComponentFilesList,\n formatPath,\n runOnce,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { IMPORT_MODE } from '@intlayer/config/defaultValues';\nimport { colorize, colorizeKey, 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\n// Plugin\n\n/**\n * Returns the Vite plugins responsible for the build optimisation step.\n *\n * Contains three internal plugins:\n *\n * 1. Vue async plugin – handles Vue SFC async script blocks.\n * 2. Usage analyser (`vite-intlayer-usage-analyzer`) – pre-scans every\n * component source file during `buildStart` to build the field-usage map\n * in `pruneContext`. This runs before any `transform` calls so the\n * downstream prune plugin always has complete data.\n * 3. Babel transform (`vite-intlayer-babel-transform`) – rewrites\n * `useIntlayer('key')` / `getIntlayer('key')` calls into\n * `useDictionary(_hash)` / `getDictionary(_hash)` and injects the\n * corresponding JSON (or dynamic `.mjs`) imports. Also applies field-name\n * renaming when `build.minify` is enabled.\n *\n * @param intlayerConfig - Resolved intlayer configuration.\n * @param pruneContext - Shared mutable state written here and read by the\n * prune and minify plugins. Pass `null` to skip\n * analysis (e.g. when both `purge` and `minify` are\n * disabled).\n */\nexport const intlayerOptimize = async (\n intlayerConfig: IntlayerConfig,\n pruneContext: PruneContext | null\n): Promise<PluginOption[]> => {\n try {\n const logger = getAppLogger(intlayerConfig);\n\n const { optimize, purge, minify } = intlayerConfig.build;\n const editorEnabled = intlayerConfig.editor.enabled;\n\n const importMode =\n intlayerConfig.build.importMode ?? intlayerConfig.dictionary?.importMode;\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n baseDir,\n } = 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 componentFilesList = buildComponentFilesList(intlayerConfig);\n\n const transformableFilesList = [\n ...componentFilesList,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n\n const dictionaries = getDictionaries(intlayerConfig);\n\n const dictionaryKeyToImportModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch'\n > = {};\n (Object.values(dictionaries) as Dictionary[]).forEach((dictionary) => {\n dictionaryKeyToImportModeMap[dictionary.key] =\n dictionary.importMode ?? importMode ?? IMPORT_MODE;\n });\n\n const isBuildOptimizeEnabled = (\n _config: unknown,\n env: { command: string }\n ) => {\n const isBuildCommand = env.command === 'build';\n return (optimize === undefined && isBuildCommand) || optimize === true;\n };\n\n const isAnalysisEnabled = (_config: unknown, env: { command: string }) =>\n !editorEnabled &&\n (!!purge || !!minify) &&\n isBuildOptimizeEnabled(_config, env);\n\n let partiallyMinifiedDictionariesCount = 0;\n\n return [\n intlayerVueAsyncPlugin(intlayerConfig, transformableFilesList),\n\n // Plugin 1: Usage analyser\n {\n name: 'vite-intlayer-usage-analyzer',\n enforce: 'pre',\n apply: isAnalysisEnabled,\n\n buildStart: async () => {\n if (!pruneContext) return;\n\n // Phase 1: Babel-based field-usage analysis for all component files\n await Promise.all(\n componentFilesList.map(async (sourceFilePath) => {\n if (!SOURCE_FILE_REGEX.test(sourceFilePath)) return;\n\n let sourceCode: string;\n try {\n sourceCode = await readFile(sourceFilePath, 'utf-8');\n } catch {\n return; // unreadable file – skip silently\n }\n\n if (!INTLAYER_USAGE_REGEX.test(sourceCode)) return;\n\n // For Vue/Svelte SFCs, the usage analyzer expects the raw script\n // content. `analyzeFieldUsageInFile` handles block extraction\n // internally via `extractScriptBlocks`.\n try {\n await analyzeFieldUsageInFile(\n sourceFilePath,\n sourceCode,\n pruneContext\n );\n } catch (parseError) {\n pruneContext.hasUnparsableSourceFiles = true;\n logger(\n [\n `Could not parse`,\n formatPath(sourceFilePath),\n `for field-usage analysis.`,\n 'Dictionaries whose usage cannot be confirmed will not be pruned.',\n parseError instanceof Error\n ? `(${parseError.message})`\n : String(parseError),\n ],\n { level: 'warn' }\n );\n }\n })\n );\n\n // Phase 2: Framework-specific analysis for Vue / Svelte SFC bindings\n // that Babel scope analysis cannot resolve (`.value` indirection in\n // Vue, `$` prefix in Svelte).\n if (pruneContext.pendingFrameworkAnalysis.size > 0) {\n const vuePending = new Map<\n string,\n { variableName: string; dictionaryKey: string }[]\n >();\n const sveltePending = new Map<\n string,\n { variableName: string; dictionaryKey: string }[]\n >();\n\n for (const [\n filePath,\n entries,\n ] of pruneContext.pendingFrameworkAnalysis) {\n if (filePath.endsWith('.vue')) {\n vuePending.set(filePath, entries);\n } else if (filePath.endsWith('.svelte')) {\n sveltePending.set(filePath, entries);\n }\n }\n\n /** Merge framework-extracted field usage into pruneContext. */\n const mergeFrameworkResult = (\n dictionaryKey: string,\n fields: Set<string> | undefined\n ): void => {\n if (fields && fields.size > 0) {\n // The Babel rename plugin cannot update source-code property\n // accesses for SFC indirect patterns → suppress field renaming.\n pruneContext.dictionariesSkippingFieldRename.add(dictionaryKey);\n\n const existing =\n pruneContext.dictionaryKeyToFieldUsageMap.get(dictionaryKey);\n if (existing === 'all') return;\n\n const merged =\n existing instanceof Set\n ? new Set([...existing, ...fields])\n : new Set(fields);\n pruneContext.dictionaryKeyToFieldUsageMap.set(\n dictionaryKey,\n merged\n );\n } else {\n pruneContext.dictionaryKeyToFieldUsageMap.set(\n dictionaryKey,\n 'all'\n );\n }\n };\n\n // Vue files\n if (vuePending.size > 0) {\n let extractVueIntlayerFieldUsage:\n | ((\n code: string,\n vars: { variableName: string; dictionaryKey: string }[]\n ) => Map<string, Set<string>>)\n | null = null;\n\n try {\n const vueCompiler = await import('@intlayer/vue-compiler');\n extractVueIntlayerFieldUsage =\n vueCompiler.extractVueIntlayerFieldUsage;\n } catch {\n // @intlayer/vue-compiler not installed – fall back to 'all'\n }\n\n for (const [filePath, entries] of vuePending) {\n if (!extractVueIntlayerFieldUsage) {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n let fileCode: string;\n try {\n fileCode = await readFile(filePath, 'utf-8');\n } catch {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n const result = extractVueIntlayerFieldUsage(fileCode, entries);\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(\n dictionaryKey,\n result.get(dictionaryKey)\n );\n }\n }\n }\n\n // Svelte files\n if (sveltePending.size > 0) {\n let extractSvelteIntlayerFieldUsage:\n | ((\n code: string,\n vars: { variableName: string; dictionaryKey: string }[]\n ) => Map<string, Set<string>>)\n | null = null;\n\n try {\n const svelteCompiler = await import(\n '@intlayer/svelte-compiler'\n );\n extractSvelteIntlayerFieldUsage =\n svelteCompiler.extractSvelteIntlayerFieldUsage;\n } catch {\n // @intlayer/svelte-compiler not installed – fall back to 'all'\n }\n\n for (const [filePath, entries] of sveltePending) {\n if (!extractSvelteIntlayerFieldUsage) {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n let fileCode: string;\n try {\n fileCode = await readFile(filePath, 'utf-8');\n } catch {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n const result = extractSvelteIntlayerFieldUsage(\n fileCode,\n entries\n );\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(\n dictionaryKey,\n result.get(dictionaryKey)\n );\n }\n }\n }\n }\n\n // Phase 3: Warn about untracked bindings (plain variable assignments)\n for (const [\n dictionaryKey,\n sourceFilePaths,\n ] of pruneContext.dictionaryKeysWithUntrackedBindings) {\n logger(\n [\n `Dictionary`,\n colorizeKey(dictionaryKey),\n `cannot be purged or minified.`,\n `\\n Reason: the result of`,\n `${colorize(`useIntlayer(`, ANSIColors.GREY_LIGHT)}${colorizeKey(\n `'${dictionaryKey}'`\n )}${colorize(`)`, ANSIColors.GREY_LIGHT)}`,\n `is assigned to a plain variable in:`,\n ...sourceFilePaths.map(\n (filePath) => `\\n - ${formatPath(filePath)}`\n ),\n ],\n { level: 'warn' }\n );\n }\n\n // Phase 4: Build field-rename map for minification\n // Reads each compiled dictionary JSON to discover the full nested\n // user-defined field structure, then builds a NestedRenameMap that\n // assigns short alphabetic aliases at every level.\n if (minify) {\n for (const [\n dictionaryKey,\n fieldUsage,\n ] of pruneContext.dictionaryKeyToFieldUsageMap) {\n if (fieldUsage === 'all') continue;\n\n // Fetch-mode dictionaries are served from a remote API using\n // original field names – renaming would break the client/server\n // contract.\n if (dictionaryKeyToImportModeMap[dictionaryKey] === 'fetch')\n continue;\n\n // SFC indirect access: skip field rename for these dictionaries\n // to avoid a JSON ↔ source mismatch at runtime.\n if (\n pruneContext.dictionariesSkippingFieldRename.has(dictionaryKey)\n )\n continue;\n\n // Read dictionary content (static JSON first, then dynamic per-locale)\n let dictionaryContent: unknown = null;\n\n const staticJsonPath = join(\n dictionariesDir,\n `${dictionaryKey}.json`\n );\n try {\n const raw = await readFile(staticJsonPath, 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n dictionaryContent = parsed.content;\n } catch {\n try {\n const dynamicDir = join(\n dynamicDictionariesDir,\n dictionaryKey\n );\n const localeFiles = await readdir(dynamicDir);\n const firstJsonFile = localeFiles.find((f) =>\n f.endsWith('.json')\n );\n if (firstJsonFile) {\n const raw = await readFile(\n join(dynamicDir, firstJsonFile),\n 'utf-8'\n );\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n dictionaryContent = parsed.content;\n }\n } catch {\n // Dictionary file not readable – skip rename for this key\n }\n }\n\n if (!dictionaryContent) continue;\n\n // Build the rename map from ALL user-defined fields in the\n // dictionary — not just the ones statically consumed by source\n // files. Using the full set ensures that:\n // 1. Every field in the compiled JSON is renamed (even if\n // pruned-out fields still appear when purge is disabled).\n // 2. The short-name assignment is stable: the alphabetical\n // order of all fields determines each short name, so adding\n // or removing a consumer never changes names for others.\n // 3. There is no source ↔ JSON mismatch: both sides use the\n // identical map regardless of which subset is consumed.\n const nestedRenameMap =\n buildNestedRenameMapFromContent(dictionaryContent);\n\n // Skip dictionaries whose opaque fields have nested user-defined\n // structure – renaming those sub-keys would silently break child\n // components that consume the field value as-is.\n const opaqueFieldMap =\n pruneContext.dictionaryKeysWithOpaqueTopLevelFields.get(\n dictionaryKey\n );\n\n if (opaqueFieldMap) {\n const dangerousEntries = [...opaqueFieldMap.entries()].filter(\n ([fieldName]) =>\n (nestedRenameMap.get(fieldName)?.children.size ?? 0) > 0\n );\n if (dangerousEntries.length > 0) {\n partiallyMinifiedDictionariesCount += 1;\n\n logger(\n [\n `Dictionary`,\n colorizeKey(dictionaryKey),\n `partially minified.`,\n ...dangerousEntries.flatMap(([fieldName, locations]) => [\n `\\n Opaque field:`,\n colorize(`'${fieldName}'`, ANSIColors.BLUE),\n `(nested keys preserved for stability).`,\n ...locations.map(\n (loc) => `\\n at ${formatPath(loc)}`\n ),\n ]),\n ],\n { level: 'warn', isVerbose: true }\n );\n\n // Disable renaming for the children of opaque fields to prevent\n // breaking components that receive the field as a prop.\n for (const [fieldName] of dangerousEntries) {\n const entry = nestedRenameMap.get(fieldName);\n if (entry) {\n entry.children = new Map();\n }\n }\n }\n }\n\n if (nestedRenameMap.size > 0) {\n pruneContext.dictionaryKeyToFieldRenameMap.set(\n dictionaryKey,\n nestedRenameMap\n );\n }\n }\n\n if (partiallyMinifiedDictionariesCount > 0) {\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-partial-minify-summary.lock'\n ),\n () => {\n logger([\n `Partially minified`,\n colorizeNumber(partiallyMinifiedDictionariesCount),\n `dictionar${partiallyMinifiedDictionariesCount === 1 ? 'y' : 'ies'}`,\n `(preserved nested keys for opaque fields).`,\n ]);\n },\n { cacheTimeoutMs: 1000 * 5 }\n );\n }\n }\n },\n },\n\n // Plugin 2: Babel transform\n {\n name: 'vite-intlayer-babel-transform',\n enforce: 'post', // Run after framework transformations (e.g. Vue SFC)\n apply: (_config, env) => {\n const isBuildCommand = env.command === 'build';\n const isEnabled =\n (optimize === undefined && isBuildCommand) || optimize === true;\n\n if (!isBuildCommand || !isEnabled) return false;\n\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-optimize-plugin-enabled.lock'\n ),\n () =>\n logger([\n `Build optimization ${colorize('enabled', ANSIColors.GREEN)}`,\n colorize('(import mode:', ANSIColors.GREY_DARK),\n colorize(importMode ?? IMPORT_MODE, ANSIColors.BLUE),\n colorize(')', ANSIColors.GREY_DARK),\n ]),\n { cacheTimeoutMs: 1000 * 10 }\n );\n\n return true;\n },\n\n transform: async (sourceCode, moduleId) => {\n // Strip query parameters added by Vue/Svelte loaders\n // e.g. \"HelloWorld.vue?vue&type=script&setup=true&lang.ts\" → \"HelloWorld.vue\"\n const sourceFilePath = moduleId.split('?', 1)[0];\n\n if (!SOURCE_FILE_REGEX.test(sourceFilePath)) return null;\n if (!transformableFilesList.includes(sourceFilePath)) return null;\n\n const isDictionaryEntryFile = [\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ].includes(sourceFilePath);\n\n const isUsingIntlayer = INTLAYER_USAGE_REGEX.test(sourceCode);\n if (!isUsingIntlayer && !isDictionaryEntryFile) return null;\n\n // Step 1: Field rename (must run before the optimize pass, which\n // replaces useIntlayer → useDictionary and erases the dictionary key)\n let codeToOptimize = sourceCode;\n\n if (pruneContext && isUsingIntlayer) {\n const renamedCode = await renameFieldsInSourceFile(\n sourceFilePath,\n sourceCode,\n pruneContext\n );\n if (renamedCode) {\n codeToOptimize = renamedCode;\n }\n }\n\n // Step 2: Optimize (useIntlayer('key') → useDictionary(_hash))\n const transformResult = await optimizeSourceFile(\n codeToOptimize,\n sourceFilePath,\n {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n fetchDictionariesEntryPath: join(\n mainDir,\n 'fetch_dictionaries.mjs'\n ),\n importMode,\n filesList: transformableFilesList,\n replaceDictionaryEntry: true,\n dictionaryModeMap: dictionaryKeyToImportModeMap,\n }\n );\n\n if (!transformResult) return null;\n\n console.log({\n code: transformResult.code,\n });\n\n return {\n code: transformResult.code,\n map: transformResult.map as any,\n };\n },\n },\n ];\n } catch (pluginInitError) {\n console.warn(\n '[vite-intlayer] Failed to initialise optimization plugin:',\n pluginInitError\n );\n return [];\n }\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiDA,MAAa,mBAAmB,OAC9B,gBACA,iBAC4B;AAC5B,KAAI;EACF,MAAM,SAAS,aAAa,eAAe;EAE3C,MAAM,EAAE,UAAU,OAAO,WAAW,eAAe;EACnD,MAAM,gBAAgB,eAAe,OAAO;EAE5C,MAAM,aACJ,eAAe,MAAM,cAAc,eAAe,YAAY;EAEhE,MAAM,EACJ,iBACA,wBACA,yBACA,sBACA,SACA,YACE,eAAe;EAEnB,MAAM,wBAAwB,KAAK,SAAS,mBAAmB;EAC/D,MAAM,gCAAgC,KACpC,SACA,4BACD;EACD,MAAM,+BAA+B,KACnC,SACA,2BACD;EAED,MAAM,qBAAqB,wBAAwB,eAAe;EAElE,MAAM,yBAAyB;GAC7B,GAAG;GACH;GACA;GACD;EAED,MAAM,eAAe,gBAAgB,eAAe;EAEpD,MAAM,+BAGF,EAAE;AACN,EAAC,OAAO,OAAO,aAAa,CAAkB,SAAS,eAAe;AACpE,gCAA6B,WAAW,OACtC,WAAW,cAAc,cAAc;IACzC;EAEF,MAAM,0BACJ,SACA,QACG;GACH,MAAM,iBAAiB,IAAI,YAAY;AACvC,UAAQ,aAAa,UAAa,kBAAmB,aAAa;;EAGpE,MAAM,qBAAqB,SAAkB,QAC3C,CAAC,kBACA,CAAC,CAAC,SAAS,CAAC,CAAC,WACd,uBAAuB,SAAS,IAAI;EAEtC,IAAI,qCAAqC;AAEzC,SAAO;GACL,uBAAuB,gBAAgB,uBAAuB;GAG9D;IACE,MAAM;IACN,SAAS;IACT,OAAO;IAEP,YAAY,YAAY;AACtB,SAAI,CAAC,aAAc;AAGnB,WAAM,QAAQ,IACZ,mBAAmB,IAAI,OAAO,mBAAmB;AAC/C,UAAI,CAAC,kBAAkB,KAAK,eAAe,CAAE;MAE7C,IAAI;AACJ,UAAI;AACF,oBAAa,MAAM,SAAS,gBAAgB,QAAQ;cAC9C;AACN;;AAGF,UAAI,CAAC,qBAAqB,KAAK,WAAW,CAAE;AAK5C,UAAI;AACF,aAAM,wBACJ,gBACA,YACA,aACD;eACM,YAAY;AACnB,oBAAa,2BAA2B;AACxC,cACE;QACE;QACA,WAAW,eAAe;QAC1B;QACA;QACA,sBAAsB,QAClB,IAAI,WAAW,QAAQ,KACvB,OAAO,WAAW;QACvB,EACD,EAAE,OAAO,QAAQ,CAClB;;OAEH,CACH;AAKD,SAAI,aAAa,yBAAyB,OAAO,GAAG;MAClD,MAAM,6BAAa,IAAI,KAGpB;MACH,MAAM,gCAAgB,IAAI,KAGvB;AAEH,WAAK,MAAM,CACT,UACA,YACG,aAAa,yBAChB,KAAI,SAAS,SAAS,OAAO,CAC3B,YAAW,IAAI,UAAU,QAAQ;eACxB,SAAS,SAAS,UAAU,CACrC,eAAc,IAAI,UAAU,QAAQ;;MAKxC,MAAM,wBACJ,eACA,WACS;AACT,WAAI,UAAU,OAAO,OAAO,GAAG;AAG7B,qBAAa,gCAAgC,IAAI,cAAc;QAE/D,MAAM,WACJ,aAAa,6BAA6B,IAAI,cAAc;AAC9D,YAAI,aAAa,MAAO;QAExB,MAAM,SACJ,oBAAoB,MAChB,IAAI,IAAI,CAAC,GAAG,UAAU,GAAG,OAAO,CAAC,GACjC,IAAI,IAAI,OAAO;AACrB,qBAAa,6BAA6B,IACxC,eACA,OACD;aAED,cAAa,6BAA6B,IACxC,eACA,MACD;;AAKL,UAAI,WAAW,OAAO,GAAG;OACvB,IAAI,+BAKO;AAEX,WAAI;AAEF,wCACE,MAFwB,OAAO,2BAEnB;eACR;AAIR,YAAK,MAAM,CAAC,UAAU,YAAY,YAAY;AAC5C,YAAI,CAAC,8BAA8B;AACjC,cAAK,MAAM,EAAE,mBAAmB,QAC9B,sBAAqB,eAAe,OAAU;AAEhD;;QAGF,IAAI;AACJ,YAAI;AACF,oBAAW,MAAM,SAAS,UAAU,QAAQ;gBACtC;AACN,cAAK,MAAM,EAAE,mBAAmB,QAC9B,sBAAqB,eAAe,OAAU;AAEhD;;QAGF,MAAM,SAAS,6BAA6B,UAAU,QAAQ;AAC9D,aAAK,MAAM,EAAE,mBAAmB,QAC9B,sBACE,eACA,OAAO,IAAI,cAAc,CAC1B;;;AAMP,UAAI,cAAc,OAAO,GAAG;OAC1B,IAAI,kCAKO;AAEX,WAAI;AAIF,2CACE,MAJ2B,OAC3B,8BAGe;eACX;AAIR,YAAK,MAAM,CAAC,UAAU,YAAY,eAAe;AAC/C,YAAI,CAAC,iCAAiC;AACpC,cAAK,MAAM,EAAE,mBAAmB,QAC9B,sBAAqB,eAAe,OAAU;AAEhD;;QAGF,IAAI;AACJ,YAAI;AACF,oBAAW,MAAM,SAAS,UAAU,QAAQ;gBACtC;AACN,cAAK,MAAM,EAAE,mBAAmB,QAC9B,sBAAqB,eAAe,OAAU;AAEhD;;QAGF,MAAM,SAAS,gCACb,UACA,QACD;AACD,aAAK,MAAM,EAAE,mBAAmB,QAC9B,sBACE,eACA,OAAO,IAAI,cAAc,CAC1B;;;;AAOT,UAAK,MAAM,CACT,eACA,oBACG,aAAa,oCAChB,QACE;MACE;MACA,YAAY,cAAc;MAC1B;MACA;MACA,GAAG,SAAS,gBAAgB,WAAW,WAAW,GAAG,YACnD,IAAI,cAAc,GACnB,GAAG,SAAS,KAAK,WAAW,WAAW;MACxC;MACA,GAAG,gBAAgB,KAChB,aAAa,aAAa,WAAW,SAAS,GAChD;MACF,EACD,EAAE,OAAO,QAAQ,CAClB;AAOH,SAAI,QAAQ;AACV,WAAK,MAAM,CACT,eACA,eACG,aAAa,8BAA8B;AAC9C,WAAI,eAAe,MAAO;AAK1B,WAAI,6BAA6B,mBAAmB,QAClD;AAIF,WACE,aAAa,gCAAgC,IAAI,cAAc,CAE/D;OAGF,IAAI,oBAA6B;OAEjC,MAAM,iBAAiB,KACrB,iBACA,GAAG,cAAc,OAClB;AACD,WAAI;QACF,MAAM,MAAM,MAAM,SAAS,gBAAgB,QAAQ;AAEnD,4BADe,KAAK,MAAM,IACA,CAAC;eACrB;AACN,YAAI;SACF,MAAM,aAAa,KACjB,wBACA,cACD;SAED,MAAM,iBAAgB,MADI,QAAQ,WAAW,EACX,MAAM,MACtC,EAAE,SAAS,QAAQ,CACpB;AACD,aAAI,eAAe;UACjB,MAAM,MAAM,MAAM,SAChB,KAAK,YAAY,cAAc,EAC/B,QACD;AAED,8BADe,KAAK,MAAM,IACA,CAAC;;gBAEvB;;AAKV,WAAI,CAAC,kBAAmB;OAYxB,MAAM,kBACJ,gCAAgC,kBAAkB;OAKpD,MAAM,iBACJ,aAAa,uCAAuC,IAClD,cACD;AAEH,WAAI,gBAAgB;QAClB,MAAM,mBAAmB,CAAC,GAAG,eAAe,SAAS,CAAC,CAAC,QACpD,CAAC,gBACC,gBAAgB,IAAI,UAAU,EAAE,SAAS,QAAQ,KAAK,EAC1D;AACD,YAAI,iBAAiB,SAAS,GAAG;AAC/B,+CAAsC;AAEtC,gBACE;UACE;UACA,YAAY,cAAc;UAC1B;UACA,GAAG,iBAAiB,SAAS,CAAC,WAAW,eAAe;WACtD;WACA,SAAS,IAAI,UAAU,IAAI,WAAW,KAAK;WAC3C;WACA,GAAG,UAAU,KACV,QAAQ,cAAc,WAAW,IAAI,GACvC;WACF,CAAC;UACH,EACD;UAAE,OAAO;UAAQ,WAAW;UAAM,CACnC;AAID,cAAK,MAAM,CAAC,cAAc,kBAAkB;UAC1C,MAAM,QAAQ,gBAAgB,IAAI,UAAU;AAC5C,cAAI,MACF,OAAM,2BAAW,IAAI,KAAK;;;;AAMlC,WAAI,gBAAgB,OAAO,EACzB,cAAa,8BAA8B,IACzC,eACA,gBACD;;AAIL,UAAI,qCAAqC,EACvC,SACE,KACE,SACA,aACA,SACA,uCACD,QACK;AACJ,cAAO;QACL;QACA,eAAe,mCAAmC;QAClD,YAAY,uCAAuC,IAAI,MAAM;QAC7D;QACD,CAAC;SAEJ,EAAE,gBAAgB,MAAO,GAAG,CAC7B;;;IAIR;GAGD;IACE,MAAM;IACN,SAAS;IACT,QAAQ,SAAS,QAAQ;KACvB,MAAM,iBAAiB,IAAI,YAAY;AAIvC,SAAI,CAAC,kBAAkB,EAFpB,aAAa,UAAa,kBAAmB,aAAa,MAE1B,QAAO;AAE1C,aACE,KACE,SACA,aACA,SACA,wCACD,QAEC,OAAO;MACL,sBAAsB,SAAS,WAAW,WAAW,MAAM;MAC3D,SAAS,iBAAiB,WAAW,UAAU;MAC/C,SAAS,cAAc,aAAa,WAAW,KAAK;MACpD,SAAS,KAAK,WAAW,UAAU;MACpC,CAAC,EACJ,EAAE,gBAAgB,MAAO,IAAI,CAC9B;AAED,YAAO;;IAGT,WAAW,OAAO,YAAY,aAAa;KAGzC,MAAM,iBAAiB,SAAS,MAAM,KAAK,EAAE,CAAC;AAE9C,SAAI,CAAC,kBAAkB,KAAK,eAAe,CAAE,QAAO;AACpD,SAAI,CAAC,uBAAuB,SAAS,eAAe,CAAE,QAAO;KAE7D,MAAM,wBAAwB,CAC5B,uBACA,8BACD,CAAC,SAAS,eAAe;KAE1B,MAAM,kBAAkB,qBAAqB,KAAK,WAAW;AAC7D,SAAI,CAAC,mBAAmB,CAAC,sBAAuB,QAAO;KAIvD,IAAI,iBAAiB;AAErB,SAAI,gBAAgB,iBAAiB;MACnC,MAAM,cAAc,MAAM,yBACxB,gBACA,YACA,aACD;AACD,UAAI,YACF,kBAAiB;;KAKrB,MAAM,kBAAkB,MAAM,mBAC5B,gBACA,gBACA;MACE;MACA;MACA;MACA;MACA;MACA;MACA;MACA;MACA,4BAA4B,KAC1B,SACA,yBACD;MACD;MACA,WAAW;MACX,wBAAwB;MACxB,mBAAmB;MACpB,CACF;AAED,SAAI,CAAC,gBAAiB,QAAO;AAE7B,aAAQ,IAAI,EACV,MAAM,gBAAgB,MACvB,CAAC;AAEF,YAAO;MACL,MAAM,gBAAgB;MACtB,KAAK,gBAAgB;MACtB;;IAEJ;GACF;UACM,iBAAiB;AACxB,UAAQ,KACN,6DACA,gBACD;AACD,SAAO,EAAE"}
|
|
1
|
+
{"version":3,"file":"intlayerOptimizePlugin.mjs","names":[],"sources":["../../src/intlayerOptimizePlugin.ts"],"sourcesContent":["import { readdir, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport {\n analyzeFieldUsageInFile,\n buildNestedRenameMapFromContent,\n INTLAYER_USAGE_REGEX,\n optimizeSourceFile,\n type PruneContext,\n renameFieldsInSourceFile,\n SOURCE_FILE_REGEX,\n} from '@intlayer/babel';\nimport {\n buildComponentFilesList,\n formatPath,\n runOnce,\n} from '@intlayer/chokidar/utils';\nimport * as ANSIColors from '@intlayer/config/colors';\nimport { IMPORT_MODE } from '@intlayer/config/defaultValues';\nimport { colorize, colorizeKey, 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\n// Plugin\n\n/**\n * Returns the Vite plugins responsible for the build optimisation step.\n *\n * Contains three internal plugins:\n *\n * 1. Vue async plugin – handles Vue SFC async script blocks.\n * 2. Usage analyser (`vite-intlayer-usage-analyzer`) – pre-scans every\n * component source file during `buildStart` to build the field-usage map\n * in `pruneContext`. This runs before any `transform` calls so the\n * downstream prune plugin always has complete data.\n * 3. Babel transform (`vite-intlayer-babel-transform`) – rewrites\n * `useIntlayer('key')` / `getIntlayer('key')` calls into\n * `useDictionary(_hash)` / `getDictionary(_hash)` and injects the\n * corresponding JSON (or dynamic `.mjs`) imports. Also applies field-name\n * renaming when `build.minify` is enabled.\n *\n * @param intlayerConfig - Resolved intlayer configuration.\n * @param pruneContext - Shared mutable state written here and read by the\n * prune and minify plugins. Pass `null` to skip\n * analysis (e.g. when both `purge` and `minify` are\n * disabled).\n */\nexport const intlayerOptimize = async (\n intlayerConfig: IntlayerConfig,\n pruneContext: PruneContext | null\n): Promise<PluginOption[]> => {\n try {\n const logger = getAppLogger(intlayerConfig);\n\n const { optimize, purge, minify } = intlayerConfig.build;\n const editorEnabled = intlayerConfig.editor.enabled;\n\n const importMode =\n intlayerConfig.build.importMode ?? intlayerConfig.dictionary?.importMode;\n\n const {\n dictionariesDir,\n dynamicDictionariesDir,\n unmergedDictionariesDir,\n fetchDictionariesDir,\n mainDir,\n baseDir,\n } = 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 componentFilesList = buildComponentFilesList(intlayerConfig);\n\n const transformableFilesList = [\n ...componentFilesList,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ];\n\n const dictionaries = getDictionaries(intlayerConfig);\n\n const dictionaryKeyToImportModeMap: Record<\n string,\n 'static' | 'dynamic' | 'fetch'\n > = {};\n (Object.values(dictionaries) as Dictionary[]).forEach((dictionary) => {\n dictionaryKeyToImportModeMap[dictionary.key] =\n dictionary.importMode ?? importMode ?? IMPORT_MODE;\n });\n\n const isBuildOptimizeEnabled = (\n _config: unknown,\n env: { command: string }\n ) => {\n const isBuildCommand = env.command === 'build';\n return (optimize === undefined && isBuildCommand) || optimize === true;\n };\n\n const isAnalysisEnabled = (_config: unknown, env: { command: string }) =>\n !editorEnabled &&\n (!!purge || !!minify) &&\n isBuildOptimizeEnabled(_config, env);\n\n let partiallyMinifiedDictionariesCount = 0;\n\n return [\n intlayerVueAsyncPlugin(intlayerConfig, transformableFilesList),\n\n // Plugin 1: Usage analyser\n {\n name: 'vite-intlayer-usage-analyzer',\n enforce: 'pre',\n apply: isAnalysisEnabled,\n\n buildStart: async () => {\n if (!pruneContext) return;\n\n // Phase 1: Babel-based field-usage analysis for all component files\n await Promise.all(\n componentFilesList.map(async (sourceFilePath) => {\n if (!SOURCE_FILE_REGEX.test(sourceFilePath)) return;\n\n let sourceCode: string;\n try {\n sourceCode = await readFile(sourceFilePath, 'utf-8');\n } catch {\n return; // unreadable file – skip silently\n }\n\n if (!INTLAYER_USAGE_REGEX.test(sourceCode)) return;\n\n // For Vue/Svelte SFCs, the usage analyzer expects the raw script\n // content. `analyzeFieldUsageInFile` handles block extraction\n // internally via `extractScriptBlocks`.\n try {\n await analyzeFieldUsageInFile(\n sourceFilePath,\n sourceCode,\n pruneContext\n );\n } catch (parseError) {\n pruneContext.hasUnparsableSourceFiles = true;\n logger(\n [\n `Could not parse`,\n formatPath(sourceFilePath),\n `for field-usage analysis.`,\n 'Dictionaries whose usage cannot be confirmed will not be pruned.',\n parseError instanceof Error\n ? `(${parseError.message})`\n : String(parseError),\n ],\n { level: 'warn' }\n );\n }\n })\n );\n\n // Phase 2: Framework-specific analysis for Vue / Svelte SFC bindings\n // that Babel scope analysis cannot resolve (`.value` indirection in\n // Vue, `$` prefix in Svelte).\n if (pruneContext.pendingFrameworkAnalysis.size > 0) {\n const vuePending = new Map<\n string,\n { variableName: string; dictionaryKey: string }[]\n >();\n const sveltePending = new Map<\n string,\n { variableName: string; dictionaryKey: string }[]\n >();\n\n for (const [\n filePath,\n entries,\n ] of pruneContext.pendingFrameworkAnalysis) {\n if (filePath.endsWith('.vue')) {\n vuePending.set(filePath, entries);\n } else if (filePath.endsWith('.svelte')) {\n sveltePending.set(filePath, entries);\n }\n }\n\n /** Merge framework-extracted field usage into pruneContext. */\n const mergeFrameworkResult = (\n dictionaryKey: string,\n fields: Set<string> | undefined\n ): void => {\n if (fields && fields.size > 0) {\n // The Babel rename plugin cannot update source-code property\n // accesses for SFC indirect patterns → suppress field renaming.\n pruneContext.dictionariesSkippingFieldRename.add(dictionaryKey);\n\n const existing =\n pruneContext.dictionaryKeyToFieldUsageMap.get(dictionaryKey);\n if (existing === 'all') return;\n\n const merged =\n existing instanceof Set\n ? new Set([...existing, ...fields])\n : new Set(fields);\n pruneContext.dictionaryKeyToFieldUsageMap.set(\n dictionaryKey,\n merged\n );\n } else {\n pruneContext.dictionaryKeyToFieldUsageMap.set(\n dictionaryKey,\n 'all'\n );\n }\n };\n\n // Vue files\n if (vuePending.size > 0) {\n let extractVueIntlayerFieldUsage:\n | ((\n code: string,\n vars: { variableName: string; dictionaryKey: string }[]\n ) => Map<string, Set<string>>)\n | null = null;\n\n try {\n const vueCompiler = await import('@intlayer/vue-compiler');\n extractVueIntlayerFieldUsage =\n vueCompiler.extractVueIntlayerFieldUsage;\n } catch {\n // @intlayer/vue-compiler not installed – fall back to 'all'\n }\n\n for (const [filePath, entries] of vuePending) {\n if (!extractVueIntlayerFieldUsage) {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n let fileCode: string;\n try {\n fileCode = await readFile(filePath, 'utf-8');\n } catch {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n const result = extractVueIntlayerFieldUsage(fileCode, entries);\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(\n dictionaryKey,\n result.get(dictionaryKey)\n );\n }\n }\n }\n\n // Svelte files\n if (sveltePending.size > 0) {\n let extractSvelteIntlayerFieldUsage:\n | ((\n code: string,\n vars: { variableName: string; dictionaryKey: string }[]\n ) => Map<string, Set<string>>)\n | null = null;\n\n try {\n const svelteCompiler = await import(\n '@intlayer/svelte-compiler'\n );\n extractSvelteIntlayerFieldUsage =\n svelteCompiler.extractSvelteIntlayerFieldUsage;\n } catch {\n // @intlayer/svelte-compiler not installed – fall back to 'all'\n }\n\n for (const [filePath, entries] of sveltePending) {\n if (!extractSvelteIntlayerFieldUsage) {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n let fileCode: string;\n try {\n fileCode = await readFile(filePath, 'utf-8');\n } catch {\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(dictionaryKey, undefined);\n }\n continue;\n }\n\n const result = extractSvelteIntlayerFieldUsage(\n fileCode,\n entries\n );\n for (const { dictionaryKey } of entries) {\n mergeFrameworkResult(\n dictionaryKey,\n result.get(dictionaryKey)\n );\n }\n }\n }\n }\n\n // Phase 3: Warn about untracked bindings (plain variable assignments)\n for (const [\n dictionaryKey,\n sourceFilePaths,\n ] of pruneContext.dictionaryKeysWithUntrackedBindings) {\n logger(\n [\n `Dictionary`,\n colorizeKey(dictionaryKey),\n `cannot be purged or minified.`,\n `\\n Reason: the result of`,\n `${colorize(`useIntlayer(`, ANSIColors.GREY_LIGHT)}${colorizeKey(\n `'${dictionaryKey}'`\n )}${colorize(`)`, ANSIColors.GREY_LIGHT)}`,\n `is assigned to a plain variable in:`,\n ...sourceFilePaths.map(\n (filePath) => `\\n - ${formatPath(filePath)}`\n ),\n ],\n { level: 'warn' }\n );\n }\n\n // Phase 4: Build field-rename map for minification\n // Reads each compiled dictionary JSON to discover the full nested\n // user-defined field structure, then builds a NestedRenameMap that\n // assigns short alphabetic aliases at every level.\n if (minify) {\n for (const [\n dictionaryKey,\n fieldUsage,\n ] of pruneContext.dictionaryKeyToFieldUsageMap) {\n if (fieldUsage === 'all') continue;\n\n // Fetch-mode dictionaries are served from a remote API using\n // original field names – renaming would break the client/server\n // contract.\n if (dictionaryKeyToImportModeMap[dictionaryKey] === 'fetch')\n continue;\n\n // SFC indirect access: skip field rename for these dictionaries\n // to avoid a JSON ↔ source mismatch at runtime.\n if (\n pruneContext.dictionariesSkippingFieldRename.has(dictionaryKey)\n )\n continue;\n\n // Read dictionary content (static JSON first, then dynamic per-locale)\n let dictionaryContent: unknown = null;\n\n const staticJsonPath = join(\n dictionariesDir,\n `${dictionaryKey}.json`\n );\n try {\n const raw = await readFile(staticJsonPath, 'utf-8');\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n dictionaryContent = parsed.content;\n } catch {\n try {\n const dynamicDir = join(\n dynamicDictionariesDir,\n dictionaryKey\n );\n const localeFiles = await readdir(dynamicDir);\n const firstJsonFile = localeFiles.find((f) =>\n f.endsWith('.json')\n );\n if (firstJsonFile) {\n const raw = await readFile(\n join(dynamicDir, firstJsonFile),\n 'utf-8'\n );\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n dictionaryContent = parsed.content;\n }\n } catch {\n // Dictionary file not readable – skip rename for this key\n }\n }\n\n if (!dictionaryContent) continue;\n\n // Build the rename map from ALL user-defined fields in the\n // dictionary — not just the ones statically consumed by source\n // files. Using the full set ensures that:\n // 1. Every field in the compiled JSON is renamed (even if\n // pruned-out fields still appear when purge is disabled).\n // 2. The short-name assignment is stable: the alphabetical\n // order of all fields determines each short name, so adding\n // or removing a consumer never changes names for others.\n // 3. There is no source ↔ JSON mismatch: both sides use the\n // identical map regardless of which subset is consumed.\n const nestedRenameMap =\n buildNestedRenameMapFromContent(dictionaryContent);\n\n // Skip dictionaries whose opaque fields have nested user-defined\n // structure – renaming those sub-keys would silently break child\n // components that consume the field value as-is.\n const opaqueFieldMap =\n pruneContext.dictionaryKeysWithOpaqueTopLevelFields.get(\n dictionaryKey\n );\n\n if (opaqueFieldMap) {\n const dangerousEntries = [...opaqueFieldMap.entries()].filter(\n ([fieldName]) =>\n (nestedRenameMap.get(fieldName)?.children.size ?? 0) > 0\n );\n if (dangerousEntries.length > 0) {\n partiallyMinifiedDictionariesCount += 1;\n\n logger(\n [\n `Dictionary`,\n colorizeKey(dictionaryKey),\n `partially minified.`,\n ...dangerousEntries.flatMap(([fieldName, locations]) => [\n `\\n Opaque field:`,\n colorize(`'${fieldName}'`, ANSIColors.BLUE),\n `(nested keys preserved for stability).`,\n ...locations.map(\n (loc) => `\\n at ${formatPath(loc)}`\n ),\n ]),\n ],\n { level: 'warn', isVerbose: true }\n );\n\n // Disable renaming for the children of opaque fields to prevent\n // breaking components that receive the field as a prop.\n for (const [fieldName] of dangerousEntries) {\n const entry = nestedRenameMap.get(fieldName);\n if (entry) {\n entry.children = new Map();\n }\n }\n }\n }\n\n if (nestedRenameMap.size > 0) {\n pruneContext.dictionaryKeyToFieldRenameMap.set(\n dictionaryKey,\n nestedRenameMap\n );\n }\n }\n\n if (partiallyMinifiedDictionariesCount > 0) {\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-partial-minify-summary.lock'\n ),\n () => {\n logger([\n `Partially minified`,\n colorizeNumber(partiallyMinifiedDictionariesCount),\n `dictionar${partiallyMinifiedDictionariesCount === 1 ? 'y' : 'ies'}`,\n `(preserved nested keys for opaque fields).`,\n ]);\n },\n { cacheTimeoutMs: 1000 * 5 }\n );\n }\n }\n },\n },\n\n // Plugin 2: Babel transform\n {\n name: 'vite-intlayer-babel-transform',\n enforce: 'post', // Run after framework transformations (e.g. Vue SFC)\n apply: (_config, env) => {\n const isBuildCommand = env.command === 'build';\n const isEnabled =\n (optimize === undefined && isBuildCommand) || optimize === true;\n\n if (!isBuildCommand || !isEnabled) return false;\n\n runOnce(\n join(\n baseDir,\n '.intlayer',\n 'cache',\n 'intlayer-optimize-plugin-enabled.lock'\n ),\n () =>\n logger([\n `Build optimization ${colorize('enabled', ANSIColors.GREEN)}`,\n colorize('(import mode:', ANSIColors.GREY_DARK),\n colorize(importMode ?? IMPORT_MODE, ANSIColors.BLUE),\n colorize(')', ANSIColors.GREY_DARK),\n ]),\n { cacheTimeoutMs: 1000 * 10 }\n );\n\n return true;\n },\n\n transform: async (sourceCode, moduleId) => {\n // Strip query parameters added by Vue/Svelte loaders\n // e.g. \"HelloWorld.vue?vue&type=script&setup=true&lang.ts\" → \"HelloWorld.vue\"\n const sourceFilePath = moduleId.split('?', 1)[0];\n\n if (!SOURCE_FILE_REGEX.test(sourceFilePath)) return null;\n if (!transformableFilesList.includes(sourceFilePath)) return null;\n\n const isDictionaryEntryFile = [\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n ].includes(sourceFilePath);\n\n const isUsingIntlayer = INTLAYER_USAGE_REGEX.test(sourceCode);\n if (!isUsingIntlayer && !isDictionaryEntryFile) return null;\n\n // Step 1: Field rename (must run before the optimize pass, which\n // replaces useIntlayer → useDictionary and erases the dictionary key)\n let codeToOptimize = sourceCode;\n\n if (pruneContext && isUsingIntlayer) {\n const renamedCode = await renameFieldsInSourceFile(\n sourceFilePath,\n sourceCode,\n pruneContext\n );\n if (renamedCode) {\n codeToOptimize = renamedCode;\n }\n }\n\n // Step 2: Optimize (useIntlayer('key') → useDictionary(_hash))\n const transformResult = await optimizeSourceFile(\n codeToOptimize,\n sourceFilePath,\n {\n optimize,\n dictionariesDir,\n dictionariesEntryPath,\n unmergedDictionariesEntryPath,\n unmergedDictionariesDir,\n dynamicDictionariesDir,\n dynamicDictionariesEntryPath,\n fetchDictionariesDir,\n fetchDictionariesEntryPath: join(\n mainDir,\n 'fetch_dictionaries.mjs'\n ),\n importMode,\n filesList: transformableFilesList,\n replaceDictionaryEntry: true,\n dictionaryModeMap: dictionaryKeyToImportModeMap,\n }\n );\n\n if (!transformResult) return null;\n\n return {\n code: transformResult.code,\n map: transformResult.map as any,\n };\n },\n },\n ];\n } catch (pluginInitError) {\n console.warn(\n '[vite-intlayer] Failed to initialise optimization plugin:',\n pluginInitError\n );\n return [];\n }\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-intlayer",
|
|
3
|
-
"version": "8.7.8
|
|
3
|
+
"version": "8.7.8",
|
|
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": [
|
|
@@ -76,12 +76,12 @@
|
|
|
76
76
|
"typecheck": "tsc --noEmit --project tsconfig.types.json"
|
|
77
77
|
},
|
|
78
78
|
"dependencies": {
|
|
79
|
-
"@intlayer/babel": "8.7.8
|
|
80
|
-
"@intlayer/chokidar": "8.7.8
|
|
81
|
-
"@intlayer/config": "8.7.8
|
|
82
|
-
"@intlayer/core": "8.7.8
|
|
83
|
-
"@intlayer/dictionaries-entry": "8.7.8
|
|
84
|
-
"@intlayer/types": "8.7.8
|
|
79
|
+
"@intlayer/babel": "8.7.8",
|
|
80
|
+
"@intlayer/chokidar": "8.7.8",
|
|
81
|
+
"@intlayer/config": "8.7.8",
|
|
82
|
+
"@intlayer/core": "8.7.8",
|
|
83
|
+
"@intlayer/dictionaries-entry": "8.7.8",
|
|
84
|
+
"@intlayer/types": "8.7.8"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
87
|
"@types/node": "25.6.0",
|
|
@@ -95,8 +95,8 @@
|
|
|
95
95
|
},
|
|
96
96
|
"peerDependencies": {
|
|
97
97
|
"@babel/core": ">=6.0.0",
|
|
98
|
-
"@intlayer/svelte-compiler": "8.7.8
|
|
99
|
-
"@intlayer/vue-compiler": "8.7.8
|
|
98
|
+
"@intlayer/svelte-compiler": "8.7.8",
|
|
99
|
+
"@intlayer/vue-compiler": "8.7.8",
|
|
100
100
|
"vite": ">=4.0.0"
|
|
101
101
|
},
|
|
102
102
|
"peerDependenciesMeta": {
|