diff --git a/packages/vite/src/node/__tests__/utils.spec.ts b/packages/vite/src/node/__tests__/utils.spec.ts index 1162105c3f19c7..954b72bbbf4fa5 100644 --- a/packages/vite/src/node/__tests__/utils.spec.ts +++ b/packages/vite/src/node/__tests__/utils.spec.ts @@ -1,4 +1,5 @@ import { + dropStringLiteralsFromString, getPotentialTsSrcPaths, injectQuery, isWindows, @@ -97,3 +98,25 @@ test('ts import of file with .js and query param', () => { 'test-file.js.tsx?lee=123' ]) }) + +test('drop string literals from string', () => { + const c1 = { raw: `console.log(ab)`, expected: `console.log(ab)` } + const c2 = { raw: `console.log('ab')`, expected: `console.log(' ')` } + const c3 = { + raw: `console.log(ab + "cd")`, + expected: `console.log(ab + '\0\0')` + } + const c4 = { + raw: 'console.log(`ab${cd}ef`)', + expected: 'console.log(`\0\0${cd}\0\0`)' + } + const c5 = { + raw: 'console.log(`ab${cd + "ef"}gh`)', + expected: "console.log(`\0\0${cd + '\0\0'}\0\0`)" + } + + expect(dropStringLiteralsFromString(c2.raw, ' ')).toBe(c2.expected) + ;[c1, c3, c4, c5].forEach(({ raw, expected }) => { + expect(dropStringLiteralsFromString(raw, '\0')).toBe(expected) + }) +}) diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index a3f8e441b0f933..a8999b5e21404f 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -4,10 +4,10 @@ import path from 'path' import { fileToUrl } from './asset' import type { ResolvedConfig } from '../config' import { + blankReplacer, + dropStringLiteralsFromString, multilineCommentsRE, - singlelineCommentsRE, - stringsRE, - blankReplacer + singlelineCommentsRE } from '../utils' /** @@ -34,11 +34,11 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { const noCommentsCode = code .replace(multilineCommentsRE, blankReplacer) .replace(singlelineCommentsRE, blankReplacer) - .replace(stringsRE, (m) => `'${'\0'.repeat(m.length - 2)}'`) + const noStringCode = dropStringLiteralsFromString(noCommentsCode, '\0') let s: MagicString | null = null let match: RegExpExecArray | null - while ((match = importMetaUrlRE.exec(noCommentsCode))) { + while ((match = importMetaUrlRE.exec(noStringCode))) { const { 0: exp, 1: emptyUrl, index } = match const urlStart = exp.indexOf(emptyUrl) + index diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index c9a2903d9a4142..d275d233ea87d5 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -5,10 +5,10 @@ import { fileToUrl } from './asset' import { blankReplacer, cleanUrl, + dropStringLiteralsFromString, injectQuery, multilineCommentsRE, - singlelineCommentsRE, - stringsRE + singlelineCommentsRE } from '../utils' import path from 'path' import { workerFileToUrl } from './worker' @@ -124,10 +124,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { .replace(multilineCommentsRE, blankReplacer) .replace(singlelineCommentsRE, blankReplacer) - const noStringCode = noCommentsCode.replace( - stringsRE, - (m) => `'${' '.repeat(m.length - 2)}'` - ) + const noStringCode = dropStringLiteralsFromString(noCommentsCode, ' ') let match: RegExpExecArray | null let s: MagicString | null = null while ((match = importMetaUrlRE.exec(noStringCode))) { diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index 8c7859e3850454..91cc469ac62dd4 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -733,4 +733,26 @@ export function parseRequest(id: string): Record | null { } export const blankReplacer = (match: string) => ' '.repeat(match.length) -export const stringsRE = /"[^"]*"|'[^']*'|`[^`]*`/g + +export function dropStringLiteralsFromString( + code: string, + replacer: string +): string { + let result = code + + const templateLiteralMatch = code.match(/`[^`]*`/g) + if (templateLiteralMatch) { + const templateLiteralRE = /`([^`]*)\$\{([^}]+)\}([^`]*)`/g + result = result.replace( + templateLiteralRE, + (full, prefix, variable, suffix) => { + const prefixPadding = replacer.repeat(prefix.length) + const suffixPadding = replacer.repeat(suffix.length) + return `\`${prefixPadding}\$\{${variable}\}${suffixPadding}\`` + } + ) + } + + const stringsRE = /"[^"]*"|'[^']*'/g + return result.replace(stringsRE, (m) => `'${replacer.repeat(m.length - 2)}'`) +}