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: objurl for type module, and concurrent tests #8541

Merged
merged 21 commits into from Jun 13, 2022
2 changes: 1 addition & 1 deletion packages/vite/src/node/plugins/worker.ts
Expand Up @@ -281,7 +281,7 @@ export function webWorkerPlugin(config: ResolvedConfig): Plugin {
export default function WorkerWrapper() {
const objURL = blob && (window.URL || window.webkitURL).createObjectURL(blob);
try {
return objURL ? new ${workerConstructor}(objURL${workerOptions}) : new ${workerConstructor}("data:application/javascript;base64," + encodedJs${workerOptions});
return objURL ? new ${workerConstructor}(objURL) : new ${workerConstructor}("data:application/javascript;base64," + encodedJs${workerOptions});
} finally {
objURL && (window.URL || window.webkitURL).revokeObjectURL(objURL);
}
Expand Down
Expand Up @@ -5,7 +5,8 @@ import {
getBg,
getColor,
isBuild,
page
page,
viteConfig
} from '~utils'

const absoluteAssetMatch = isBuild
Expand Down Expand Up @@ -137,7 +138,8 @@ describe('css url() references', () => {
describe.runIf(isBuild)('index.css URLs', () => {
let css: string
beforeAll(() => {
css = findAssetFile(/index.*\.css$/, '', 'other-assets')
const base = viteConfig ? viteConfig?.testConfig?.baseRoute : ''
css = findAssetFile(/index.*\.css$/, base, 'other-assets')
})

test('relative asset URL', () => {
Expand Down
8 changes: 6 additions & 2 deletions playground/assets/vite.config-relative-base.js
Expand Up @@ -8,7 +8,7 @@ module.exports = {
base: './', // relative base to make dist portable
build: {
...baseConfig.build,
outDir: 'dist',
outDir: 'dist/relative-base',
watch: false,
minify: false,
assetsInlineLimit: 0,
Expand All @@ -19,5 +19,9 @@ module.exports = {
assetFileNames: 'other-assets/[name].[hash][extname]'
}
}
}
},
testConfig: {
baseRoute: '/relative-base/'
},
cacheDir: 'node_modules/.vite/relative-base'
}
3 changes: 2 additions & 1 deletion playground/assets/vite.config.js
Expand Up @@ -17,5 +17,6 @@ module.exports = {
assetsInlineLimit: 8192, // 8kb
manifest: true,
watch: {}
}
},
cacheDir: 'node_modules/.vite/foo'
}
6 changes: 3 additions & 3 deletions playground/test-utils.ts
Expand Up @@ -150,7 +150,7 @@ export async function untilUpdated(
runInBuild = false
): Promise<void> {
if (isBuild && !runInBuild) return
const maxTries = process.env.CI ? 100 : 50
const maxTries = process.env.CI ? 200 : 50
for (let tries = 0; tries < maxTries; tries++) {
const actual = (await poll()) ?? ''
if (actual.indexOf(expected) > -1 || tries === maxTries - 1) {
Expand All @@ -162,12 +162,12 @@ export async function untilUpdated(
}
}

export const extractSourcemap = (content: string) => {
export const extractSourcemap = (content: string): any => {
const lines = content.trim().split('\n')
return fromComment(lines[lines.length - 1]).toObject()
}

export const formatSourcemapForSnapshot = (map: any) => {
export const formatSourcemapForSnapshot = (map: any): any => {
const root = normalizePath(testDir)
const m = { ...map }
delete m.file
Expand Down
4 changes: 2 additions & 2 deletions playground/vitestGlobalSetup.ts
Expand Up @@ -8,7 +8,7 @@ const DIR = path.join(os.tmpdir(), 'vitest_playwright_global_setup')

let browserServer: BrowserServer | undefined

export async function setup() {
export async function setup(): Promise<void> {
browserServer = await chromium.launchServer({
headless: !process.env.VITE_DEBUG_SERVE,
args: process.env.CI
Expand Down Expand Up @@ -41,7 +41,7 @@ export async function setup() {
})
}

export async function teardown() {
export async function teardown(): Promise<void> {
browserServer?.close()
if (!process.env.VITE_PRESERVE_BUILD_ARTIFACTS) {
fs.removeSync(path.resolve(__dirname, '../playground-temp'))
Expand Down
41 changes: 32 additions & 9 deletions playground/vitestSetup.ts
@@ -1,7 +1,6 @@
import * as http from 'http'
import { dirname, resolve } from 'path'
import path, { dirname, resolve } from 'path'
import os from 'os'
import path from 'path'
import sirv from 'sirv'
import fs from 'fs-extra'
import { chromium } from 'playwright-chromium'
Expand All @@ -25,7 +24,10 @@ export const workspaceRoot = path.resolve(__dirname, '../')
export const isBuild = !!process.env.VITE_TEST_BUILD
export const isServe = !isBuild
export const isWindows = process.platform === 'win32'
export const viteBinPath = path.join(workspaceRoot, 'packages/vite/bin/vite.js')
export const viteBinPath = path.posix.join(
workspaceRoot,
'packages/vite/bin/vite.js'
)

// #endregion

Expand All @@ -49,6 +51,11 @@ export let testDir: string
* Test folder name
*/
export let testName: string
/**
* current test using vite inline config
* when using server.js is not possible to get the config
*/
export let viteConfig: InlineConfig | undefined

export const serverLogs: string[] = []
export const browserLogs: string[] = []
Expand All @@ -61,7 +68,17 @@ export let browser: Browser = undefined!
export let viteTestUrl: string = ''
export let watcher: RollupWatcher | undefined = undefined

export function setViteUrl(url: string) {
declare module 'vite' {
interface InlineConfig {
testConfig?: {
// relative base output use relative path
// rewrite the url to truth file path
baseRoute: string
}
}
}

export function setViteUrl(url: string): void {
viteTestUrl = url
}

Expand Down Expand Up @@ -156,7 +173,7 @@ beforeAll(async (s) => {
}
})

export async function startDefaultServe() {
export async function startDefaultServe(): Promise<void> {
const testCustomConfig = resolve(dirname(testPath), 'vite.config.js')
let config: InlineConfig | undefined
if (fs.existsSync(testCustomConfig)) {
Expand Down Expand Up @@ -193,9 +210,9 @@ export async function startDefaultServe() {

if (!isBuild) {
process.env.VITE_INLINE = 'inline-serve'
server = await (
await createServer(mergeConfig(options, config || {}))
).listen()
const testConfig = mergeConfig(options, config || {})
viteConfig = testConfig
server = await (await createServer(testConfig)).listen()
// use resolved port/base from server
const base = server.config.base === '/' ? '' : server.config.base
viteTestUrl = `http://localhost:${server.config.server.port}${base}`
Expand All @@ -210,7 +227,9 @@ export async function startDefaultServe() {
}
})
options.plugins = [resolvedPlugin()]
const rollupOutput = await build(mergeConfig(options, config || {}))
const testConfig = mergeConfig(options, config || {})
viteConfig = testConfig
const rollupOutput = await build(testConfig)
const isWatch = !!resolvedConfig!.build.watch
// in build watch,call startStaticServer after the build is complete
if (isWatch) {
Expand Down Expand Up @@ -245,11 +264,15 @@ function startStaticServer(config?: InlineConfig): Promise<string> {

// start static file server
const serve = sirv(resolve(rootDir, 'dist'), { dev: !!config?.build?.watch })
const baseDir = config?.testConfig?.baseRoute
const httpServer = (server = http.createServer((req, res) => {
if (req.url === '/ping') {
res.statusCode = 200
res.end('pong')
} else {
if (baseDir) {
req.url = path.posix.join(baseDir, req.url)
}
serve(req, res)
}
}))
Expand Down
119 changes: 66 additions & 53 deletions playground/worker/__tests__/es/es-worker.spec.ts
@@ -1,63 +1,48 @@
import fs from 'fs'
import path from 'path'
import type { Page } from 'playwright-chromium'
import { isBuild, page, testDir, untilUpdated } from '~utils'

test('normal', async () => {
await page.click('.ping')
await untilUpdated(() => page.textContent('.pong'), 'pong')
await untilUpdated(() => page.textContent('.pong'), 'pong', true)
await untilUpdated(
() => page.textContent('.mode'),
process.env.NODE_ENV // match workerImport.js
process.env.NODE_ENV,
true
)
await untilUpdated(
() => page.textContent('.bundle-with-plugin'),
'worker bundle with plugin success!'
'worker bundle with plugin success!',
true
)
})

test('TS output', async () => {
await page.click('.ping-ts-output')
await untilUpdated(() => page.textContent('.pong-ts-output'), 'pong')
await untilUpdated(() => page.textContent('.pong-ts-output'), 'pong', true)
})

test('inlined', async () => {
await page.click('.ping-inline')
await untilUpdated(() => page.textContent('.pong-inline'), 'pong')
await untilUpdated(() => page.textContent('.pong-inline'), 'pong', true)
})

const waitSharedWorkerTick = (
(resolvedSharedWorkerCount: number) => async (page: Page) => {
await untilUpdated(async () => {
const count = await page.textContent('.tick-count')
// ignore the initial 0
return count === '1' ? 'page loaded' : ''
}, 'page loaded')
// test.concurrent sequential is not guaranteed
// force page to wait to ensure two pages overlap in time
resolvedSharedWorkerCount++
if (resolvedSharedWorkerCount < 2) return

await untilUpdated(() => {
return resolvedSharedWorkerCount === 2 ? 'all pages loaded' : ''
}, 'all pages loaded')
}
)(0)

test.each([[true], [false]])('shared worker', async (doTick) => {
if (doTick) {
await page.click('.tick-shared')
}
await waitSharedWorkerTick(page)
test('shared worker', async () => {
await untilUpdated(() => page.textContent('.tick-count'), 'pong', true)
})

test('worker emitted and import.meta.url in nested worker (serve)', async () => {
expect(await page.textContent('.nested-worker')).toMatch(
'worker-nested-worker'
await untilUpdated(
() => page.textContent('.nested-worker'),
'worker-nested-worker',
true
)
expect(await page.textContent('.nested-worker-module')).toMatch('sub-worker')
expect(await page.textContent('.nested-worker-constructor')).toMatch(
'"type":"constructor"'
await untilUpdated(
() => page.textContent('.nested-worker-module'),
'sub-worker',
true
)
await untilUpdated(
() => page.textContent('.nested-worker-constructor'),
'"type":"constructor"',
true
)
})

Expand Down Expand Up @@ -87,45 +72,73 @@ describe.runIf(isBuild)('build', () => {
})

test('worker emitted and import.meta.url in nested worker (build)', async () => {
expect(await page.textContent('.nested-worker-module')).toMatch(
'"type":"module"'
await untilUpdated(
() => page.textContent('.nested-worker-module'),
'"type":"module"',
true
)
expect(await page.textContent('.nested-worker-constructor')).toMatch(
'"type":"constructor"'
await untilUpdated(
() => page.textContent('.nested-worker-constructor'),
'"type":"constructor"',
true
)
})
})

test('module worker', async () => {
expect(await page.textContent('.shared-worker-import-meta-url')).toMatch(
'A string'
await untilUpdated(
() => page.textContent('.shared-worker-import-meta-url'),
'A string',
true
)
})

test('classic worker', async () => {
expect(await page.textContent('.classic-worker')).toMatch('A classic')
expect(await page.textContent('.classic-shared-worker')).toMatch('A classic')
await untilUpdated(
() => page.textContent('.classic-worker'),
'A classic',
true
)
await untilUpdated(
() => page.textContent('.classic-shared-worker'),
'A classic',
true
)
})

test('emit chunk', async () => {
expect(await page.textContent('.emit-chunk-worker')).toMatch(
'["A string",{"type":"emit-chunk-sub-worker","data":"A string"},{"type":"module-and-worker:worker","data":"A string"},{"type":"module-and-worker:module","data":"module and worker"},{"type":"emit-chunk-sub-worker","data":{"module":"module and worker","msg1":"module1","msg2":"module2","msg3":"module3"}}]'
await untilUpdated(
() => page.textContent('.emit-chunk-worker'),
'["A string",{"type":"emit-chunk-sub-worker","data":"A string"},{"type":"module-and-worker:worker","data":"A string"},{"type":"module-and-worker:module","data":"module and worker"},{"type":"emit-chunk-sub-worker","data":{"module":"module and worker","msg1":"module1","msg2":"module2","msg3":"module3"}}]',
true
)
expect(await page.textContent('.emit-chunk-dynamic-import-worker')).toMatch(
'"A string/es/"'
await untilUpdated(
() => page.textContent('.emit-chunk-dynamic-import-worker'),
'"A string/es/"',
true
)
})

test('url query worker', async () => {
expect(await page.textContent('.simple-worker-url')).toMatch(
'Hello from simple worker!'
await untilUpdated(
() => page.textContent('.simple-worker-url'),
'Hello from simple worker!',
true
)
})

test('import.meta.glob in worker', async () => {
expect(await page.textContent('.importMetaGlob-worker')).toMatch('["')
await untilUpdated(
() => page.textContent('.importMetaGlob-worker'),
'["',
true
)
})

test('import.meta.glob with eager in worker', async () => {
expect(await page.textContent('.importMetaGlobEager-worker')).toMatch('["')
await untilUpdated(
() => page.textContent('.importMetaGlobEager-worker'),
'["',
true
)
})