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: legacy no resolve asset urls #9507

Merged
merged 42 commits into from Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8900c1c
test: vue legacy
poyoho Aug 3, 2022
b9130cc
feat: resolveAssetUrlsInCss in legacy mode
poyoho Aug 3, 2022
536cd5e
feat: test hook for legacy
poyoho Aug 4, 2022
72d8aef
fix: relative path for legacy mode
poyoho Aug 5, 2022
d909dee
fix: test
poyoho Aug 5, 2022
6e08b1d
feat: ignore entry chunk insert css
poyoho Aug 6, 2022
c1eb9b0
fix: error
poyoho Aug 6, 2022
a0caa7c
chore: update comment
poyoho Aug 6, 2022
18bec1b
chore: update
poyoho Aug 10, 2022
0b4c3cc
chore: update
poyoho Aug 10, 2022
fb734fa
chore: update
poyoho Aug 10, 2022
53bfcf6
chore: revert avoid generate the css insert script
poyoho Aug 10, 2022
43c64ae
chore: update
poyoho Aug 10, 2022
2d7812a
chore: update
poyoho Aug 10, 2022
f684b78
chore: renderAssetUrl helper
poyoho Aug 16, 2022
b6083fb
chore: update
poyoho Aug 16, 2022
2fd5069
fix: cssAssetDirname
poyoho Aug 16, 2022
2ae6788
chore: rebase
poyoho Aug 16, 2022
46d57b0
feat: opts
poyoho Aug 16, 2022
1a50884
fix: types
poyoho Aug 16, 2022
ecd950b
chore: don't modify resolveAssetUrlsInCss
poyoho Aug 17, 2022
57b3595
chore: revert resolveAssetUrlsInCss
poyoho Aug 17, 2022
e91fe24
chore: update
poyoho Aug 17, 2022
86af81d
chore: update
poyoho Aug 17, 2022
45dfb22
feat: no wrap
poyoho Aug 17, 2022
32fbeb3
chore: update
poyoho Aug 17, 2022
b682325
chore: update
poyoho Aug 17, 2022
297b765
chore: update
poyoho Aug 17, 2022
9e179df
fix: test
poyoho Aug 17, 2022
59f6a26
chore: update
poyoho Aug 17, 2022
b30a5c9
feat: vitest __test__ hooks
poyoho Aug 17, 2022
7f49b78
fix: systemjs wrapper
poyoho Aug 17, 2022
8422fbc
feat: one more judge
poyoho Aug 17, 2022
58eeb69
chore: update
poyoho Aug 18, 2022
7e97059
chore: update
poyoho Aug 18, 2022
e3c098e
test: for async legacy chunk
poyoho Aug 18, 2022
8e95e3f
feat: systemjsWrapCompletePlugin
poyoho Aug 18, 2022
4b0b731
chore: update
poyoho Aug 18, 2022
0307aeb
chore: update
poyoho Aug 18, 2022
9c1a625
chore: update
poyoho Aug 18, 2022
3b72036
chore: update
poyoho Aug 19, 2022
8df22e9
chore: update
poyoho Aug 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/vite/src/node/build.ts
Expand Up @@ -50,6 +50,7 @@ import { watchPackageDataPlugin } from './packages'
import { ensureWatchPlugin } from './plugins/ensureWatch'
import { ESBUILD_MODULES_TARGET, VERSION } from './constants'
import { resolveChokidarOptions } from './watch'
import { completeSystemWrapPlugin } from './plugins/completeSystemWrap'

export interface BuildOptions {
/**
Expand Down Expand Up @@ -305,6 +306,7 @@ export function resolveBuildPlugins(config: ResolvedConfig): {
commonjsOptions?.include.length !== 0
return {
pre: [
completeSystemWrapPlugin(),
...(options.watch ? [ensureWatchPlugin()] : []),
watchPackageDataPlugin(config),
...(usePluginCommonjs ? [commonjsPlugin(options.commonjsOptions)] : []),
Expand Down Expand Up @@ -857,6 +859,7 @@ const relativeUrlMechanisms: Record<
)} : ${getRelativeUrlFromDocument(relativePath)})`,
es: (relativePath) => getResolveUrl(`'${relativePath}', import.meta.url`),
iife: (relativePath) => getRelativeUrlFromDocument(relativePath),
// NOTE: make sure rollup generate `module` params
system: (relativePath) => getResolveUrl(`'${relativePath}', module.meta.url`),
umd: (relativePath) =>
`(typeof document === 'undefined' && typeof location === 'undefined' ? ${getResolveUrl(
Expand Down
140 changes: 79 additions & 61 deletions packages/vite/src/node/plugins/asset.ts
Expand Up @@ -2,7 +2,13 @@ import path from 'node:path'
import { parse as parseUrl } from 'node:url'
import fs, { promises as fsp } from 'node:fs'
import * as mrmime from 'mrmime'
import type { OutputOptions, PluginContext, PreRenderedAsset } from 'rollup'
import type {
NormalizedOutputOptions,
OutputOptions,
PluginContext,
PreRenderedAsset,
RenderedChunk
} from 'rollup'
import MagicString from 'magic-string'
import { toOutputFilePathInString } from '../build'
import type { Plugin } from '../plugin'
Expand Down Expand Up @@ -36,6 +42,76 @@ export function registerCustomMime(): void {
mrmime.mimes['eot'] = 'application/vnd.ms-fontobject'
}

export function renderAssetUrlInJS(
ctx: PluginContext,
config: ResolvedConfig,
chunk: RenderedChunk,
opts: NormalizedOutputOptions,
code: string
): MagicString | undefined {
let match: RegExpExecArray | null
let s: MagicString | undefined

// Urls added with JS using e.g.
// imgElement.src = "__VITE_ASSET__5aa0ddc0__" are using quotes

// Urls added in CSS that is imported in JS end up like
// var inlined = ".inlined{color:green;background:url(__VITE_ASSET__5aa0ddc0__)}\n";

// In both cases, the wrapping should already be fine

while ((match = assetUrlRE.exec(code))) {
s ||= new MagicString(code)
const [full, hash, postfix = ''] = match
// some internal plugins may still need to emit chunks (e.g. worker) so
// fallback to this.getFileName for that. TODO: remove, not needed
const file = getAssetFilename(hash, config) || ctx.getFileName(hash)
chunk.viteMetadata.importedAssets.add(cleanUrl(file))
const filename = file + postfix
const replacement = toOutputFilePathInString(
filename,
'asset',
chunk.fileName,
'js',
config,
opts.format
)
const replacementString =
typeof replacement === 'string'
? JSON.stringify(replacement).slice(1, -1)
: `"+${replacement.runtime}+"`
s.overwrite(match.index, match.index + full.length, replacementString, {
contentOnly: true
})
}

// Replace __VITE_PUBLIC_ASSET__5aa0ddc0__ with absolute paths

const publicAssetUrlMap = publicAssetUrlCache.get(config)!
while ((match = publicAssetUrlRE.exec(code))) {
s ||= new MagicString(code)
const [full, hash] = match
const publicUrl = publicAssetUrlMap.get(hash)!.slice(1)
const replacement = toOutputFilePathInString(
publicUrl,
'public',
chunk.fileName,
'js',
config,
opts.format
)
const replacementString =
typeof replacement === 'string'
? JSON.stringify(replacement).slice(1, -1)
: `"+${replacement.runtime}+"`
s.overwrite(match.index, match.index + full.length, replacementString, {
contentOnly: true
})
}

return s
}

/**
* Also supports loading plain strings with import text from './foo.txt?raw'
*/
Expand Down Expand Up @@ -90,66 +166,8 @@ export function assetPlugin(config: ResolvedConfig): Plugin {
return `export default ${JSON.stringify(url)}`
},

renderChunk(code, chunk, outputOptions) {
let match: RegExpExecArray | null
let s: MagicString | undefined

// Urls added with JS using e.g.
// imgElement.src = "__VITE_ASSET__5aa0ddc0__" are using quotes

// Urls added in CSS that is imported in JS end up like
// var inlined = ".inlined{color:green;background:url(__VITE_ASSET__5aa0ddc0__)}\n";

// In both cases, the wrapping should already be fine

while ((match = assetUrlRE.exec(code))) {
s = s || (s = new MagicString(code))
const [full, hash, postfix = ''] = match
// some internal plugins may still need to emit chunks (e.g. worker) so
// fallback to this.getFileName for that. TODO: remove, not needed
const file = getAssetFilename(hash, config) || this.getFileName(hash)
chunk.viteMetadata.importedAssets.add(cleanUrl(file))
const filename = file + postfix
const replacement = toOutputFilePathInString(
filename,
'asset',
chunk.fileName,
'js',
config,
outputOptions.format
)
const replacementString =
typeof replacement === 'string'
? JSON.stringify(replacement).slice(1, -1)
: `"+${replacement.runtime}+"`
s.overwrite(match.index, match.index + full.length, replacementString, {
contentOnly: true
})
}

// Replace __VITE_PUBLIC_ASSET__5aa0ddc0__ with absolute paths

const publicAssetUrlMap = publicAssetUrlCache.get(config)!
while ((match = publicAssetUrlRE.exec(code))) {
s = s || (s = new MagicString(code))
const [full, hash] = match
const publicUrl = publicAssetUrlMap.get(hash)!.slice(1)
const replacement = toOutputFilePathInString(
publicUrl,
'public',
chunk.fileName,
'js',
config,
outputOptions.format
)
const replacementString =
typeof replacement === 'string'
? JSON.stringify(replacement).slice(1, -1)
: `"+${replacement.runtime}+"`
s.overwrite(match.index, match.index + full.length, replacementString, {
contentOnly: true
})
}
renderChunk(code, chunk, opts) {
const s = renderAssetUrlInJS(this, config, chunk, opts, code)

if (s) {
return {
Expand Down
23 changes: 23 additions & 0 deletions packages/vite/src/node/plugins/completeSystemWrap.ts
@@ -0,0 +1,23 @@
import type { Plugin } from '../plugin'

/**
* make sure systemjs register wrap to had complete parameters in system format
*/
export function completeSystemWrapPlugin(): Plugin {
const SystemJSWrapRE = /System.register\(.*\((exports)\)/g

return {
name: 'vite:force-systemjs-wrap-complete',

renderChunk(code, chunk, opts) {
if (opts.format === 'system') {
return {
code: code.replace(SystemJSWrapRE, (s, s1) =>
s.replace(s1, 'exports, module')
),
map: null
}
}
}
}
}
26 changes: 17 additions & 9 deletions packages/vite/src/node/plugins/css.ts
Expand Up @@ -55,6 +55,7 @@ import {
publicAssetUrlCache,
publicAssetUrlRE,
publicFileToBuiltUrl,
renderAssetUrlInJS,
resolveAssetFileNames
} from './asset'
import type { ESBuildOptions } from './esbuild'
Expand Down Expand Up @@ -556,27 +557,34 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin {
})
chunk.viteMetadata.importedCss.add(this.getFileName(fileHandle))
} else if (!config.build.ssr) {
// legacy build and inline css

// __VITE_ASSET__ and __VITE_PUBLIC_ASSET__ urls are processed by
// the vite:asset plugin, don't call resolveAssetUrlsInCss here
chunkCSS = await finalizeCss(chunkCSS, true, config)

let cssString = JSON.stringify(chunkCSS)
cssString =
renderAssetUrlInJS(
this,
config,
chunk,
opts,
cssString
)?.toString() || cssString
const style = `__vite_style__`
const injectCode =
`var ${style} = document.createElement('style');` +
`${style}.innerHTML = ${JSON.stringify(chunkCSS)};` +
`${style}.innerHTML = ${cssString};` +
`document.head.appendChild(${style});`
const wrapIdx = code.indexOf('System.register')
const insertMark = "'use strict';"
const insertIdx = code.indexOf(insertMark, wrapIdx)
const s = new MagicString(code)
s.appendLeft(insertIdx + insertMark.length, injectCode)
if (config.build.sourcemap) {
const s = new MagicString(code)
s.prepend(injectCode)
// resolve public URL from CSS paths, we need to use absolute paths
return {
code: s.toString(),
map: s.generateMap({ hires: true })
}
} else {
return { code: injectCode + code }
return { code: s.toString() }
}
}
} else {
Expand Down
11 changes: 9 additions & 2 deletions playground/vitestSetup.ts
Expand Up @@ -243,12 +243,15 @@ export async function startDefaultServe(): Promise<void> {
watcher = rollupOutput as RollupWatcher
await notifyRebuildComplete(watcher)
}
viteTestUrl = await startStaticServer(config)
viteTestUrl = await startStaticServer(resolvedConfig, config)
await page.goto(viteTestUrl)
}
}

function startStaticServer(config?: InlineConfig): Promise<string> {
function startStaticServer(
resolved: ResolvedConfig,
config?: InlineConfig
): Promise<string> {
if (!config) {
// check if the test project has base config
const configFile = resolve(rootDir, 'vite.config.js')
Expand All @@ -267,6 +270,10 @@ function startStaticServer(config?: InlineConfig): Promise<string> {
if (config && config.__test__) {
// @ts-ignore
config.__test__()
// @ts-ignore
} else if (resolved && resolved.__test__) {
// @ts-ignore
resolved.__test__()
}

// start static file server
Expand Down
32 changes: 32 additions & 0 deletions playground/vue-legacy/Main.vue
@@ -0,0 +1,32 @@
<script>
import { defineComponent, defineAsyncComponent } from 'vue'
import css from './inline.css?inline'

export default defineComponent({
components: {
module: defineAsyncComponent(() => import('./module.vue'))
},
setup() {
return {
css
}
}
})
</script>
<template>
<div class="main">
<p>Main.vue</p>
<module />
<code>
{{ css }}
</code>
</div>
</template>
<style scoped>
.main {
height: 100vh;
background: url('@/assets/asset.png') no-repeat;
poyoho marked this conversation as resolved.
Show resolved Hide resolved
background-size: contain;
background-position: center;
}
</style>
10 changes: 10 additions & 0 deletions playground/vue-legacy/__tests__/vue-legacy.spec.ts
@@ -0,0 +1,10 @@
import { test } from 'vitest'
import { getBg, untilUpdated } from '~utils'

test('vue legacy assets', async () => {
await untilUpdated(() => getBg('.main'), 'assets/asset', true)
})

test('async vue legacy assets', async () => {
await untilUpdated(() => getBg('.module'), 'assets/asset', true)
poyoho marked this conversation as resolved.
Show resolved Hide resolved
})
Binary file added playground/vue-legacy/assets/asset.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions playground/vue-legacy/env.d.ts
@@ -0,0 +1 @@
declare module '*.png'
7 changes: 7 additions & 0 deletions playground/vue-legacy/index.html
@@ -0,0 +1,7 @@
<div id="app" style="background: 'white'"></div>
<script type="module">
import { createApp } from 'vue'
import App from './Main.vue'

createApp(App).mount('#app')
</script>
3 changes: 3 additions & 0 deletions playground/vue-legacy/inline.css
@@ -0,0 +1,3 @@
.inline-css {
color: #0088ff;
}
13 changes: 13 additions & 0 deletions playground/vue-legacy/module.vue
@@ -0,0 +1,13 @@
<template>
<div class="module">
<p>module.vue</p>
</div>
</template>
<style scoped>
.module {
height: 100vh;
background: url('@/assets/asset.png') no-repeat;
background-size: contain;
background-position: center;
}
</style>
18 changes: 18 additions & 0 deletions playground/vue-legacy/package.json
@@ -0,0 +1,18 @@
{
"name": "test-vue-legacy",
"private": true,
"version": "0.0.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"debug": "node --inspect-brk ../../packages/vite/bin/vite",
"preview": "vite preview"
},
"dependencies": {
"vue": "^3.2.37"
},
"devDependencies": {
"@vitejs/plugin-vue": "workspace:*",
"@vitejs/plugin-legacy": "workspace:*"
}
}