Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(plugin-legacy): prevent dead code elimination from env.LEGACY marker #2000

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion packages/playground/legacy/__tests__/legacy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,22 @@ test('should work', async () => {
})

test('import.meta.env.LEGACY', async () => {
expect(await page.textContent('#env')).toMatch(isBuild ? 'true' : 'false')
if (isBuild) {
expect(await page.textContent('#env')).toMatch('true')

const modernSrc = await page.$eval(
'script[type="module-disabled"]',
(el: HTMLScriptElement) => el.src
)

// false after the modern chunk was executed
await page.addScriptTag({ url: modernSrc, type: 'module' })
expect(await page.textContent('#env')).toMatch('false')

// reload so execution of the modern chunk can't mess with other tests
await page.reload()
} else {
// always false in dev
expect(await page.textContent('#env')).toMatch('false')
}
})
13 changes: 10 additions & 3 deletions packages/playground/legacy/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ async function run() {

run()

document.getElementById('env').textContent = `is legacy: ${
import.meta.env.LEGACY
}`
let isLegacy

// make sure that branching works despite esbuild's constant folding (#1999)
if (import.meta.env.LEGACY) {
if (import.meta.env.LEGACY === true) isLegacy = true
} else {
if (import.meta.env.LEGACY === false) isLegacy = false
}

document.getElementById('env').textContent = `is legacy: ${isLegacy}`
4 changes: 2 additions & 2 deletions packages/playground/legacy/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ module.exports = {
},

// special test only hook
// for tests, remove `<script type="module">` tags and remove `nomodule`
// for tests, disable `<script type="module">` tags and remove `nomodule`
// attrs so that we run the legacy bundle instead.
__test__() {
const indexPath = path.resolve(__dirname, './dist/index.html')
let index = fs.readFileSync(indexPath, 'utf-8')
index = index
.replace(/<script type="module".*?<\/script>/g, '')
.replace(/<script type="module"/g, '<script type="module-disabled"')
.replace(/<script nomodule/g, '<script')
fs.writeFileSync(indexPath, index)
}
Expand Down
30 changes: 19 additions & 11 deletions packages/plugin-legacy/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ const safari10NoModuleFix = `!function(){var e=document,t=e.createElement("scrip
const legacyEntryId = 'vite-legacy-entry'
const systemJSInlineCode = `System.import(document.getElementById('${legacyEntryId}').getAttribute('data-src'))`

const legacyEnvVarMarker = `__VITE_IS_LEGACY__`
// use array instead of string to prevent esbuild constant folding, which would turn
// `if (legacyEnvVarMarker)` into `if (true)` even before the marker is replaced (#1999)
const legacyEnvVarMarker = ['__VITE_IS_LEGACY__']
const legacyEnvVarMarkerString = JSON.stringify(legacyEnvVarMarker)

const escapeRegExp = (str) => str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')

/**
* @param {import('.').Options} options
Expand Down Expand Up @@ -188,15 +193,15 @@ function viteLegacyPlugin(options = {}) {
detectPolyfills(raw, { esmodules: true }, modernPolyfills)
}

if (raw.includes(legacyEnvVarMarker)) {
const re = new RegExp(`"${legacyEnvVarMarker}"`, 'g')
if (raw.includes(legacyEnvVarMarkerString)) {
const re = new RegExp(escapeRegExp(legacyEnvVarMarkerString), 'g')
if (config.build.sourcemap) {
const s = new MagicString(raw)
let match
while ((match = re.exec(raw))) {
s.overwrite(
match.index,
match.index + legacyEnvVarMarker.length + 2,
match.index + legacyEnvVarMarkerString.length,
`false`
)
}
Expand Down Expand Up @@ -367,7 +372,7 @@ function viteLegacyPlugin(options = {}) {
}
}

let envInjectionFaled = false
let envInjectionFailed = false
/**
* @type {import('vite').Plugin}
*/
Expand All @@ -383,12 +388,12 @@ function viteLegacyPlugin(options = {}) {
}
}
} else {
envInjectionFaled = true
envInjectionFailed = true
}
},

configResolved(config) {
if (envInjectionFaled) {
if (envInjectionFailed) {
config.logger.warn(
`[@vitejs/plugin-legacy] import.meta.env.LEGACY was not injected due ` +
`to incompatible vite version (requires vite@^2.0.0-beta.69).`
Expand Down Expand Up @@ -550,10 +555,13 @@ function replaceLegacyEnvBabelPlugin() {
return ({ types: t }) => ({
name: 'vite-replace-env-legacy',
visitor: {
StringLiteral(path) {
if (path.node.value === legacyEnvVarMarker) {
path.replaceWith(t.booleanLiteral(true))
}
ArrayExpression(path) {
const firstChild = path.node.elements[0]

if (!firstChild || !t.isStringLiteral(firstChild)) return
if (firstChild.value !== legacyEnvVarMarker[0]) return

path.replaceWith(t.booleanLiteral(true))
}
}
})
Expand Down