mirror of
https://github.com/vitest-dev/vitest.git
synced 2026-02-01 17:36:51 +00:00
feat: allow importing CSS and assets inside external dependencies (#3880)
This commit is contained in:
parent
47f5c3a625
commit
f4e6e99fa3
@ -196,7 +196,7 @@ When Vitest encounters the external library listed in `include`, it will be bund
|
||||
- Your `alias` configuration is now respected inside bundled packages
|
||||
- Code in your tests is running closer to how it's running in the browser
|
||||
|
||||
Be aware that only packages in `deps.optimizer?.[mode].include` option are bundled (some plugins populate this automatically, like Svelte). You can read more about available options in [Vite](https://vitejs.dev/config/dep-optimization-options.html) docs. By default, Vitest uses `optimizer.web` for `jsdom` and `happy-dom` environments, and `optimizer.ssr` for `node` and `edge` environments, but it is configurable by [`transformMode`](#transformmode).
|
||||
Be aware that only packages in `deps.optimizer?.[mode].include` option are bundled (some plugins populate this automatically, like Svelte). You can read more about available options in [Vite](https://vitejs.dev/config/dep-optimization-options.html) docs (Vitest doesn't support `disable` and `noDiscovery` options). By default, Vitest uses `optimizer.web` for `jsdom` and `happy-dom` environments, and `optimizer.ssr` for `node` and `edge` environments, but it is configurable by [`transformMode`](#transformmode).
|
||||
|
||||
This options also inherits your `optimizeDeps` configuration (for web Vitest will extend `optimizeDeps`, for ssr - `ssr.optimizeDeps`). If you redefine `include`/`exclude` option in `deps.optimizer` it will extend your `optimizeDeps` when running tests. Vitest automatically removes the same options from `include`, if they are listed in `exclude`.
|
||||
|
||||
@ -204,6 +204,61 @@ This options also inherits your `optimizeDeps` configuration (for web Vitest wil
|
||||
You will not be able to edit your `node_modules` code for debugging, since the code is actually located in your `cacheDir` or `test.cache.dir` directory. If you want to debug with `console.log` statements, edit it directly or force rebundling with `deps.optimizer?.[mode].force` option.
|
||||
:::
|
||||
|
||||
#### deps.optimizer.{mode}.enabled
|
||||
|
||||
- **Type:** `boolean`
|
||||
- **Default:** `true`
|
||||
|
||||
Enable dependency optimization.
|
||||
|
||||
#### deps.web
|
||||
|
||||
- **Type:** `{ transformAssets?, ... }`
|
||||
- **Version:** Since Vite 0.34.2
|
||||
|
||||
Options that are applied to external files when transform mode is set to `web`. By default, `jsdom` and `happy-dom` use `web` mode, while `node` and `edge` environments use `ssr` transform mode, so these options will have no affect on files inside those environments.
|
||||
|
||||
Usually, files inside `node_modules` are externalized, but these options also affect files in [`server.deps.external`](#server-deps-external).
|
||||
|
||||
#### deps.web.transformAssets
|
||||
|
||||
- **Type:** `boolean`
|
||||
- **Default:** `true`
|
||||
|
||||
Should Vitest process assets (.png, .svg, .jpg, etc) files and resolve them like Vite does in the browser.
|
||||
|
||||
hese module will have a default export equal to the path to the asset, if no query is specified.
|
||||
|
||||
::: warning
|
||||
At the moment, this option only works with [`experimentalVmThreads`](#experimentalvmthreads) pool.
|
||||
:::
|
||||
|
||||
#### deps.web.transformCss
|
||||
|
||||
- **Type:** `boolean`
|
||||
- **Default:** `true`
|
||||
|
||||
Should Vitest process CSS (.css, .scss, .sass, etc) files and resolve them like Vite does in the browser.
|
||||
|
||||
If CSS files are disabled with [`css`](#css) options, this option will just silence `UNKNOWN_EXTENSION` errors.
|
||||
|
||||
::: warning
|
||||
At the moment, this option only works with [`experimentalVmThreads`](#experimentalvmthreads) pool.
|
||||
:::
|
||||
|
||||
#### deps.web.transformGlobPattern
|
||||
|
||||
- **Type:** `RegExp | RegExp[]`
|
||||
- **Default:** `[]`
|
||||
|
||||
Regexp pattern to match external files that should be transformed.
|
||||
|
||||
By default, files inside `node_modules` are externalized and not transformed, unless it's CSS or an asset, and corresponding option is not disabled.
|
||||
|
||||
::: warning
|
||||
At the moment, this option only works with [`experimentalVmThreads`](#experimentalvmthreads) pool.
|
||||
:::
|
||||
|
||||
#### deps.registerNodeLoader<NonProjectOption />
|
||||
|
||||
- **Type:** `boolean`
|
||||
|
||||
@ -150,6 +150,19 @@ export class ViteNodeServer {
|
||||
return this.transformPromiseMap.get(id)!
|
||||
}
|
||||
|
||||
async transformModule(id: string, transformMode?: 'web' | 'ssr') {
|
||||
if (transformMode !== 'web')
|
||||
throw new Error('`transformModule` only supports `transformMode: "web"`.')
|
||||
|
||||
const normalizedId = normalizeModuleId(id)
|
||||
const mod = this.server.moduleGraph.getModuleById(normalizedId)
|
||||
const result = mod?.transformResult || await this.server.transformRequest(normalizedId)
|
||||
|
||||
return {
|
||||
code: result?.code,
|
||||
}
|
||||
}
|
||||
|
||||
getTransformMode(id: string) {
|
||||
const withoutQuery = id.split('?')[0]
|
||||
|
||||
|
||||
@ -137,6 +137,11 @@ export function resolveConfig(
|
||||
if (!resolved.deps.moduleDirectories.includes('/node_modules/'))
|
||||
resolved.deps.moduleDirectories.push('/node_modules/')
|
||||
|
||||
resolved.deps.web ??= {}
|
||||
resolved.deps.web.transformAssets ??= true
|
||||
resolved.deps.web.transformCss ??= true
|
||||
resolved.deps.web.transformGlobPattern ??= []
|
||||
|
||||
resolved.server ??= {}
|
||||
resolved.server.deps ??= {}
|
||||
|
||||
|
||||
@ -30,6 +30,9 @@ export function createMethodsRPC(project: WorkspaceProject): RuntimeRPC {
|
||||
resolveId(id, importer, transformMode) {
|
||||
return project.vitenode.resolveId(id, importer, transformMode)
|
||||
},
|
||||
transform(id, environment) {
|
||||
return project.vitenode.transformModule(id, environment)
|
||||
},
|
||||
onPathsCollected(paths) {
|
||||
ctx.state.collectPaths(paths)
|
||||
project.report('onPathsCollected', paths)
|
||||
|
||||
@ -14,7 +14,7 @@ import type { WorkspaceProject } from '../workspace'
|
||||
import { createMethodsRPC } from './rpc'
|
||||
|
||||
const workerPath = pathToFileURL(resolve(distDir, './vm.js')).href
|
||||
const suppressLoaderWarningsPath = resolve(rootDir, './suppress-warnings.cjs')
|
||||
const suppressWarningsPath = resolve(rootDir, './suppress-warnings.cjs')
|
||||
|
||||
function createWorkerChannel(project: WorkspaceProject) {
|
||||
const channel = new MessageChannel()
|
||||
@ -61,7 +61,7 @@ export function createVmThreadsPool(ctx: Vitest, { execArgv, env }: PoolProcessO
|
||||
'--experimental-import-meta-resolve',
|
||||
'--experimental-vm-modules',
|
||||
'--require',
|
||||
suppressLoaderWarningsPath,
|
||||
suppressWarningsPath,
|
||||
...execArgv,
|
||||
],
|
||||
|
||||
|
||||
@ -293,10 +293,10 @@ export class WorkspaceProject {
|
||||
...this.config.deps,
|
||||
optimizer: {
|
||||
web: {
|
||||
enabled: this.config.deps?.optimizer?.web?.enabled ?? false,
|
||||
enabled: this.config.deps?.optimizer?.web?.enabled ?? true,
|
||||
},
|
||||
ssr: {
|
||||
enabled: this.config.deps?.optimizer?.ssr?.enabled ?? false,
|
||||
enabled: this.config.deps?.optimizer?.ssr?.enabled ?? true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@ -6,7 +6,7 @@ import type { ViteNodeRunnerOptions } from 'vite-node'
|
||||
import { normalize, relative, resolve } from 'pathe'
|
||||
import { processError } from '@vitest/utils/error'
|
||||
import type { MockMap } from '../types/mocker'
|
||||
import type { ResolvedConfig, ResolvedTestEnvironment, WorkerGlobalState } from '../types'
|
||||
import type { ResolvedConfig, ResolvedTestEnvironment, RuntimeRPC, WorkerGlobalState } from '../types'
|
||||
import { distDir } from '../paths'
|
||||
import { getWorkerState } from '../utils/global'
|
||||
import { VitestMocker } from './mocker'
|
||||
@ -21,6 +21,7 @@ export interface ExecuteOptions extends ViteNodeRunnerOptions {
|
||||
moduleDirectories?: string[]
|
||||
context?: vm.Context
|
||||
state: WorkerGlobalState
|
||||
transform: RuntimeRPC['transform']
|
||||
}
|
||||
|
||||
export async function createVitestExecutor(options: ExecuteOptions) {
|
||||
@ -100,6 +101,9 @@ export async function startVitestExecutor(options: ContextExecutorOptions) {
|
||||
resolveId(id, importer) {
|
||||
return rpc().resolveId(id, importer, getTransformMode())
|
||||
},
|
||||
transform(id) {
|
||||
return rpc().transform(id, 'web')
|
||||
},
|
||||
packageCache,
|
||||
moduleCache,
|
||||
mockMap,
|
||||
@ -174,12 +178,6 @@ export class VitestExecutor extends ViteNodeRunner {
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.externalModules = new ExternalModulesExecutor({
|
||||
...options,
|
||||
fileMap,
|
||||
context: options.context,
|
||||
packageCache: options.packageCache,
|
||||
})
|
||||
const clientStub = vm.runInContext(
|
||||
`(defaultClient) => ({ ...defaultClient, updateStyle: ${updateStyle.toString()}, removeStyle: ${removeStyle.toString()} })`,
|
||||
options.context,
|
||||
@ -189,6 +187,12 @@ export class VitestExecutor extends ViteNodeRunner {
|
||||
'@vite/client': clientStub,
|
||||
}
|
||||
this.primitives = vm.runInContext('({ Object, Reflect, Symbol })', options.context)
|
||||
this.externalModules = new ExternalModulesExecutor({
|
||||
...options,
|
||||
fileMap,
|
||||
context: options.context,
|
||||
packageCache: options.packageCache,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import { CommonjsExecutor } from './vm/commonjs-executor'
|
||||
import type { FileMap } from './vm/file-map'
|
||||
import { EsmExecutor } from './vm/esm-executor'
|
||||
import { interopCommonJsModule } from './vm/utils'
|
||||
import { ViteExecutor } from './vm/vite-executor'
|
||||
|
||||
const SyntheticModule: typeof VMSyntheticModule = (vm as any).SyntheticModule
|
||||
|
||||
@ -23,12 +24,20 @@ export interface ExternalModulesExecutorOptions extends ExecuteOptions {
|
||||
packageCache: Map<string, any>
|
||||
}
|
||||
|
||||
interface ModuleInformation {
|
||||
type: 'data' | 'builtin' | 'vite' | 'module' | 'commonjs'
|
||||
url: string
|
||||
path: string
|
||||
}
|
||||
|
||||
// TODO: improve Node.js strict mode support in #2854
|
||||
export class ExternalModulesExecutor {
|
||||
private cjs: CommonjsExecutor
|
||||
private esm: EsmExecutor
|
||||
private vite: ViteExecutor
|
||||
private context: vm.Context
|
||||
private fs: FileMap
|
||||
private resolvers: ((id: string, parent: string) => string | undefined)[] = []
|
||||
|
||||
constructor(private options: ExternalModulesExecutorOptions) {
|
||||
this.context = options.context
|
||||
@ -42,6 +51,13 @@ export class ExternalModulesExecutor {
|
||||
importModuleDynamically: this.importModuleDynamically,
|
||||
fileMap: options.fileMap,
|
||||
})
|
||||
this.vite = new ViteExecutor({
|
||||
esmExecutor: this.esm,
|
||||
context: this.context,
|
||||
transform: options.transform,
|
||||
viteClientModule: options.requestStubs!['/@vite/client'],
|
||||
})
|
||||
this.resolvers = [this.vite.resolve]
|
||||
}
|
||||
|
||||
// dynamic import can be used in both ESM and CJS, so we have it in the executor
|
||||
@ -56,6 +72,11 @@ export class ExternalModulesExecutor {
|
||||
}
|
||||
|
||||
public async resolve(specifier: string, parent: string) {
|
||||
for (const resolver of this.resolvers) {
|
||||
const id = resolver(specifier, parent)
|
||||
if (id)
|
||||
return id
|
||||
}
|
||||
return nativeResolve(specifier, parent)
|
||||
}
|
||||
|
||||
@ -124,44 +145,59 @@ export class ExternalModulesExecutor {
|
||||
return m
|
||||
}
|
||||
|
||||
private async createModule(identifier: string): Promise<VMModule> {
|
||||
private getModuleInformation(identifier: string): ModuleInformation {
|
||||
if (identifier.startsWith('data:'))
|
||||
return this.esm.createDataModule(identifier)
|
||||
return { type: 'data', url: identifier, path: identifier }
|
||||
|
||||
const extension = extname(identifier)
|
||||
|
||||
if (extension === '.node' || isNodeBuiltin(identifier)) {
|
||||
const exports = this.require(identifier)
|
||||
return this.wrapCoreSynteticModule(identifier, exports)
|
||||
}
|
||||
if (extension === '.node' || isNodeBuiltin(identifier))
|
||||
return { type: 'builtin', url: identifier, path: identifier }
|
||||
|
||||
const isFileUrl = identifier.startsWith('file://')
|
||||
const fileUrl = isFileUrl ? identifier : pathToFileURL(identifier).toString()
|
||||
const pathUrl = isFileUrl ? fileURLToPath(identifier.split('?')[0]) : identifier
|
||||
const fileUrl = isFileUrl ? identifier : pathToFileURL(pathUrl).toString()
|
||||
|
||||
// TODO: support wasm in the future
|
||||
// if (extension === '.wasm') {
|
||||
// const source = this.readBuffer(pathUrl)
|
||||
// const wasm = this.loadWebAssemblyModule(source, fileUrl)
|
||||
// this.moduleCache.set(fileUrl, wasm)
|
||||
// return wasm
|
||||
// }
|
||||
|
||||
if (extension === '.cjs') {
|
||||
const exports = this.require(pathUrl)
|
||||
return this.wrapCommonJsSynteticModule(fileUrl, exports)
|
||||
let type: 'module' | 'commonjs' | 'vite'
|
||||
if (this.vite.canResolve(fileUrl)) {
|
||||
type = 'vite'
|
||||
}
|
||||
else if (extension === '.mjs') {
|
||||
type = 'module'
|
||||
}
|
||||
else if (extension === '.cjs') {
|
||||
type = 'commonjs'
|
||||
}
|
||||
else {
|
||||
const pkgData = this.findNearestPackageData(normalize(pathUrl))
|
||||
type = pkgData.type === 'module' ? 'module' : 'commonjs'
|
||||
}
|
||||
|
||||
if (extension === '.mjs')
|
||||
return await this.esm.createEsmModule(fileUrl, this.fs.readFile(pathUrl))
|
||||
return { type, path: pathUrl, url: fileUrl }
|
||||
}
|
||||
|
||||
const pkgData = this.findNearestPackageData(normalize(pathUrl))
|
||||
private async createModule(identifier: string): Promise<VMModule> {
|
||||
const { type, url, path } = this.getModuleInformation(identifier)
|
||||
|
||||
if (pkgData.type === 'module')
|
||||
return await this.esm.createEsmModule(fileUrl, this.fs.readFile(pathUrl))
|
||||
|
||||
const exports = this.cjs.require(pathUrl)
|
||||
return this.wrapCommonJsSynteticModule(fileUrl, exports)
|
||||
switch (type) {
|
||||
case 'data':
|
||||
return this.esm.createDataModule(identifier)
|
||||
case 'builtin': {
|
||||
const exports = this.require(identifier)
|
||||
return this.wrapCoreSynteticModule(identifier, exports)
|
||||
}
|
||||
case 'vite':
|
||||
return await this.vite.createViteModule(url)
|
||||
case 'module':
|
||||
return await this.esm.createEsModule(url, this.fs.readFile(path))
|
||||
case 'commonjs': {
|
||||
const exports = this.require(path)
|
||||
return this.wrapCommonJsSynteticModule(identifier, exports)
|
||||
}
|
||||
default: {
|
||||
const _deadend: never = type
|
||||
return _deadend
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async import(identifier: string) {
|
||||
|
||||
@ -21,7 +21,8 @@ interface PrivateNodeModule extends NodeModule {
|
||||
|
||||
export class CommonjsExecutor {
|
||||
private context: vm.Context
|
||||
private requireCache: Record<string, NodeModule> = Object.create(null)
|
||||
private requireCache = new Map<string, NodeModule>()
|
||||
private publicRequireCache = this.createProxyCache()
|
||||
|
||||
private moduleCache = new Map<string, VMModule | Promise<VMModule>>()
|
||||
private builtinCache: Record<string, NodeModule> = Object.create(null)
|
||||
@ -75,7 +76,7 @@ export class CommonjsExecutor {
|
||||
script.identifier = filename
|
||||
const fn = script.runInContext(executor.context)
|
||||
const __dirname = dirname(filename)
|
||||
executor.requireCache[filename] = this
|
||||
executor.requireCache.set(filename, this)
|
||||
try {
|
||||
fn(this.exports, this.require, this, filename, __dirname)
|
||||
return this.exports
|
||||
@ -165,14 +166,31 @@ export class CommonjsExecutor {
|
||||
set: () => {},
|
||||
configurable: true,
|
||||
})
|
||||
require.main = _require.main
|
||||
require.cache = this.requireCache
|
||||
require.main = undefined // there is no main, since we are running tests using ESM
|
||||
require.cache = this.publicRequireCache
|
||||
return require
|
||||
}
|
||||
|
||||
private createProxyCache() {
|
||||
return new Proxy(Object.create(null), {
|
||||
defineProperty: () => true,
|
||||
deleteProperty: () => true,
|
||||
set: () => true,
|
||||
get: (_, key: string) => this.requireCache.get(key),
|
||||
has: (_, key: string) => this.requireCache.has(key),
|
||||
ownKeys: () => Array.from(this.requireCache.keys()),
|
||||
getOwnPropertyDescriptor() {
|
||||
return {
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// very naive implementation for Node.js require
|
||||
private loadCommonJSModule(module: NodeModule, filename: string): Record<string, unknown> {
|
||||
const cached = this.requireCache[filename]
|
||||
const cached = this.requireCache.get(filename)
|
||||
if (cached)
|
||||
return cached.exports
|
||||
|
||||
|
||||
@ -1,19 +1,14 @@
|
||||
/* eslint-disable antfu/no-cjs-exports */
|
||||
|
||||
import vm from 'node:vm'
|
||||
import { CSS_LANGS_RE, KNOWN_ASSET_RE } from 'vite-node/constants'
|
||||
import { extname, normalize } from 'pathe'
|
||||
import { getColors } from '@vitest/utils'
|
||||
import type vm from 'node:vm'
|
||||
import type { ExternalModulesExecutor } from '../external-executor'
|
||||
import type { VMModule, VMSourceTextModule, VMSyntheticModule } from './types'
|
||||
import type { VMModule } from './types'
|
||||
import { SourceTextModule, SyntheticModule } from './utils'
|
||||
|
||||
interface EsmExecutorOptions {
|
||||
context: vm.Context
|
||||
}
|
||||
|
||||
const SyntheticModule: typeof VMSyntheticModule = (vm as any).SyntheticModule
|
||||
const SourceTextModule: typeof VMSourceTextModule = (vm as any).SourceTextModule
|
||||
|
||||
const dataURIRegex
|
||||
= /^data:(?<mime>text\/javascript|application\/json|application\/wasm)(?:;(?<encoding>charset=utf-8|base64))?,(?<code>.*)$/
|
||||
|
||||
@ -45,42 +40,10 @@ export class EsmExecutor {
|
||||
return m
|
||||
}
|
||||
|
||||
public async createEsmModule(fileUrl: string, code: string) {
|
||||
public async createEsModule(fileUrl: string, code: string) {
|
||||
const cached = this.moduleCache.get(fileUrl)
|
||||
if (cached)
|
||||
return cached
|
||||
const [urlPath] = fileUrl.split('?')
|
||||
if (CSS_LANGS_RE.test(urlPath) || KNOWN_ASSET_RE.test(urlPath)) {
|
||||
const path = normalize(urlPath)
|
||||
let name = path.split('/node_modules/').pop() || ''
|
||||
if (name?.startsWith('@'))
|
||||
name = name.split('/').slice(0, 2).join('/')
|
||||
else
|
||||
name = name.split('/')[0]
|
||||
const ext = extname(path)
|
||||
let error = `[vitest] Cannot import ${fileUrl}. At the moment, importing ${ext} files inside external dependencies is not allowed. `
|
||||
if (name) {
|
||||
const c = getColors()
|
||||
error += 'As a temporary workaround you can try to inline the package by updating your config:'
|
||||
+ `\n\n${
|
||||
c.gray(c.dim('// vitest.config.js'))
|
||||
}\n${
|
||||
c.green(`export default {
|
||||
test: {
|
||||
deps: {
|
||||
optimizer: {
|
||||
web: {
|
||||
include: [
|
||||
${c.yellow(c.bold(`"${name}"`))}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}\n`)}`
|
||||
}
|
||||
throw new Error(error)
|
||||
}
|
||||
// TODO: should not be allowed in strict mode, implement in #2854
|
||||
if (fileUrl.endsWith('.json')) {
|
||||
const m = new SyntheticModule(
|
||||
@ -156,6 +119,14 @@ c.green(`export default {
|
||||
return syntheticModule
|
||||
}
|
||||
|
||||
public cacheModule(identifier: string, module: VMModule) {
|
||||
this.moduleCache.set(identifier, module)
|
||||
}
|
||||
|
||||
public resolveCachedModule(identifier: string) {
|
||||
return this.moduleCache.get(identifier)
|
||||
}
|
||||
|
||||
public async createDataModule(identifier: string): Promise<VMModule> {
|
||||
const cached = this.moduleCache.get(identifier)
|
||||
if (cached)
|
||||
@ -206,6 +177,6 @@ c.green(`export default {
|
||||
return module
|
||||
}
|
||||
|
||||
return this.createEsmModule(identifier, code)
|
||||
return this.createEsModule(identifier, code)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import vm from 'node:vm'
|
||||
import { isPrimitive } from 'vite-node/utils'
|
||||
import type { VMSourceTextModule, VMSyntheticModule } from './types'
|
||||
|
||||
export function interopCommonJsModule(interopDefault: boolean | undefined, mod: any) {
|
||||
if (isPrimitive(mod) || Array.isArray(mod) || mod instanceof Promise) {
|
||||
@ -31,3 +33,6 @@ export function interopCommonJsModule(interopDefault: boolean | undefined, mod:
|
||||
defaultExport: mod,
|
||||
}
|
||||
}
|
||||
|
||||
export const SyntheticModule: typeof VMSyntheticModule = (vm as any).SyntheticModule
|
||||
export const SourceTextModule: typeof VMSourceTextModule = (vm as any).SourceTextModule
|
||||
|
||||
101
packages/vitest/src/runtime/vm/vite-executor.ts
Normal file
101
packages/vitest/src/runtime/vm/vite-executor.ts
Normal file
@ -0,0 +1,101 @@
|
||||
import type vm from 'node:vm'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { normalize } from 'pathe'
|
||||
import { CSS_LANGS_RE, KNOWN_ASSET_RE } from 'vite-node/constants'
|
||||
import { toArray } from 'vite-node/utils'
|
||||
import type { RuntimeRPC } from '../../types/rpc'
|
||||
import type { WorkerGlobalState } from '../../types'
|
||||
import type { EsmExecutor } from './esm-executor'
|
||||
import { SyntheticModule } from './utils'
|
||||
|
||||
interface ViteExecutorOptions {
|
||||
context: vm.Context
|
||||
transform: RuntimeRPC['transform']
|
||||
esmExecutor: EsmExecutor
|
||||
viteClientModule: Record<string, unknown>
|
||||
}
|
||||
|
||||
const CLIENT_ID = '/@vite/client'
|
||||
const CLIENT_FILE = pathToFileURL(CLIENT_ID).href
|
||||
|
||||
export class ViteExecutor {
|
||||
private esm: EsmExecutor
|
||||
|
||||
constructor(private options: ViteExecutorOptions) {
|
||||
this.esm = options.esmExecutor
|
||||
}
|
||||
|
||||
public resolve = (identifier: string, parent: string) => {
|
||||
if (identifier === CLIENT_ID) {
|
||||
if (this.workerState.environment.transformMode === 'web')
|
||||
return identifier
|
||||
const packageName = this.getPackageName(parent)
|
||||
throw new Error(
|
||||
`[vitest] Vitest cannot handle ${CLIENT_ID} imported in ${parent} when running in SSR environment. Add "${packageName}" to "ssr.noExternal" if you are using Vite SSR, or to "server.deps.inline" if you are using Vite Node.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
get workerState(): WorkerGlobalState {
|
||||
return this.options.context.__vitest_worker__
|
||||
}
|
||||
|
||||
private getPackageName(modulePath: string) {
|
||||
const path = normalize(modulePath)
|
||||
let name = path.split('/node_modules/').pop() || ''
|
||||
if (name?.startsWith('@'))
|
||||
name = name.split('/').slice(0, 2).join('/')
|
||||
else
|
||||
name = name.split('/')[0]
|
||||
return name
|
||||
}
|
||||
|
||||
public async createViteModule(fileUrl: string) {
|
||||
if (fileUrl === CLIENT_FILE)
|
||||
return this.createViteClientModule()
|
||||
const cached = this.esm.resolveCachedModule(fileUrl)
|
||||
if (cached)
|
||||
return cached
|
||||
const result = await this.options.transform(fileUrl, 'web')
|
||||
if (!result.code)
|
||||
throw new Error(`[vitest] Failed to transform ${fileUrl}. Does the file exists?`)
|
||||
return this.esm.createEsModule(fileUrl, result.code)
|
||||
}
|
||||
|
||||
private createViteClientModule() {
|
||||
const identifier = CLIENT_ID
|
||||
const cached = this.esm.resolveCachedModule(identifier)
|
||||
if (cached)
|
||||
return cached
|
||||
const stub = this.options.viteClientModule
|
||||
const moduleKeys = Object.keys(stub)
|
||||
const module = new SyntheticModule(
|
||||
moduleKeys,
|
||||
() => {
|
||||
moduleKeys.forEach((key) => {
|
||||
module.setExport(key, stub[key])
|
||||
})
|
||||
},
|
||||
{ context: this.options.context, identifier },
|
||||
)
|
||||
this.esm.cacheModule(identifier, module)
|
||||
return module
|
||||
}
|
||||
|
||||
public canResolve = (fileUrl: string) => {
|
||||
const transformMode = this.workerState.environment.transformMode
|
||||
if (transformMode !== 'web')
|
||||
return false
|
||||
if (fileUrl === CLIENT_FILE)
|
||||
return true
|
||||
const config = this.workerState.config.deps?.web || {}
|
||||
const [modulePath] = fileUrl.split('?')
|
||||
if (config.transformCss && CSS_LANGS_RE.test(modulePath))
|
||||
return true
|
||||
if (config.transformAssets && KNOWN_ASSET_RE.test(modulePath))
|
||||
return true
|
||||
if (toArray(config.transformGlobPattern).some(pattern => pattern.test(modulePath)))
|
||||
return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -106,6 +106,38 @@ interface DepsOptions {
|
||||
web?: DepsOptimizationOptions
|
||||
ssr?: DepsOptimizationOptions
|
||||
}
|
||||
web?: {
|
||||
/**
|
||||
* Should Vitest process assets (.png, .svg, .jpg, etc) files and resolve them like Vite does in the browser.
|
||||
*
|
||||
* These module will have a default export equal to the path to the asset, if no query is specified.
|
||||
*
|
||||
* **At the moment, this option only works with `experimentalVmThreads` pool.**
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
transformAssets?: boolean
|
||||
/**
|
||||
* Should Vitest process CSS (.css, .scss, .sass, etc) files and resolve them like Vite does in the browser.
|
||||
*
|
||||
* If CSS files are disabled with `css` options, this option will just silence UNKNOWN_EXTENSION errors.
|
||||
*
|
||||
* **At the moment, this option only works with `experimentalVmThreads` pool.**
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
transformCss?: boolean
|
||||
/**
|
||||
* Regexp pattern to match external files that should be transformed.
|
||||
*
|
||||
* By default, files inside `node_modules` are externalized and not transformed.
|
||||
*
|
||||
* **At the moment, this option only works with `experimentalVmThreads` pool.**
|
||||
*
|
||||
* @default []
|
||||
*/
|
||||
transformGlobPattern?: RegExp | RegExp[]
|
||||
}
|
||||
/**
|
||||
* Externalize means that Vite will bypass the package to native Node.
|
||||
*
|
||||
|
||||
@ -10,6 +10,7 @@ type TransformMode = 'web' | 'ssr'
|
||||
|
||||
export interface RuntimeRPC {
|
||||
fetch: (id: string, environment: TransformMode) => Promise<FetchResult>
|
||||
transform: (id: string, environment: TransformMode) => Promise<FetchResult>
|
||||
resolveId: (id: string, importer: string | undefined, environment: TransformMode) => Promise<ViteNodeResolveId | null>
|
||||
getSourceMap: (id: string, force?: boolean) => Promise<RawSourceMap | undefined>
|
||||
|
||||
|
||||
172
pnpm-lock.yaml
generated
172
pnpm-lock.yaml
generated
@ -1963,6 +1963,9 @@ importers:
|
||||
|
||||
test/vm-threads:
|
||||
devDependencies:
|
||||
jsdom:
|
||||
specifier: latest
|
||||
version: 22.1.0
|
||||
vitest:
|
||||
specifier: workspace:*
|
||||
version: link:../../packages/vitest
|
||||
@ -2342,11 +2345,6 @@ packages:
|
||||
dependencies:
|
||||
'@babel/highlight': 7.22.5
|
||||
|
||||
/@babel/compat-data@7.22.5:
|
||||
resolution: {integrity: sha512-4Jc/YuIaYqKnDDz892kPIledykKg12Aw1PYX5i/TY28anJtacvM1Rrr8wbieB9GfEJwlzqT0hUEao0CxEebiDA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/@babel/compat-data@7.22.9:
|
||||
resolution: {integrity: sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -2474,16 +2472,6 @@ packages:
|
||||
jsesc: 2.5.2
|
||||
dev: true
|
||||
|
||||
/@babel/generator@7.22.5:
|
||||
resolution: {integrity: sha512-+lcUbnTRhd0jOewtFSedLyiPsD5tswKkbgcezOqqWFUVNEwoUTlpPOBmvhG7OXWLR4jMdv0czPGH5XbflnD1EA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.22.5
|
||||
'@jridgewell/gen-mapping': 0.3.2
|
||||
'@jridgewell/trace-mapping': 0.3.18
|
||||
jsesc: 2.5.2
|
||||
dev: true
|
||||
|
||||
/@babel/generator@7.22.9:
|
||||
resolution: {integrity: sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -2514,11 +2502,11 @@ packages:
|
||||
peerDependencies:
|
||||
'@babel/core': ^7.0.0
|
||||
dependencies:
|
||||
'@babel/compat-data': 7.22.5
|
||||
'@babel/compat-data': 7.22.9
|
||||
'@babel/core': 7.18.13
|
||||
'@babel/helper-validator-option': 7.22.5
|
||||
browserslist: 4.21.3
|
||||
semver: 6.3.0
|
||||
browserslist: 4.21.10
|
||||
semver: 6.3.1
|
||||
dev: true
|
||||
|
||||
/@babel/helper-compilation-targets@7.22.9(@babel/core@7.18.13):
|
||||
@ -2589,7 +2577,7 @@ packages:
|
||||
'@babel/helper-optimise-call-expression': 7.18.6
|
||||
'@babel/helper-replace-supers': 7.20.7
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.20.0
|
||||
'@babel/helper-split-export-declaration': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -2608,7 +2596,7 @@ packages:
|
||||
'@babel/helper-optimise-call-expression': 7.18.6
|
||||
'@babel/helper-replace-supers': 7.20.7
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.20.0
|
||||
'@babel/helper-split-export-declaration': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -2627,7 +2615,7 @@ packages:
|
||||
'@babel/helper-optimise-call-expression': 7.18.6
|
||||
'@babel/helper-replace-supers': 7.20.7
|
||||
'@babel/helper-skip-transparent-expression-wrappers': 7.20.0
|
||||
'@babel/helper-split-export-declaration': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -2755,10 +2743,10 @@ packages:
|
||||
'@babel/helper-environment-visitor': 7.22.5
|
||||
'@babel/helper-module-imports': 7.22.5
|
||||
'@babel/helper-simple-access': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.6
|
||||
'@babel/helper-validator-identifier': 7.22.5
|
||||
'@babel/template': 7.22.5
|
||||
'@babel/traverse': 7.22.5
|
||||
'@babel/traverse': 7.22.8
|
||||
'@babel/types': 7.22.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -2904,13 +2892,6 @@ packages:
|
||||
'@babel/types': 7.22.5
|
||||
dev: true
|
||||
|
||||
/@babel/helper-split-export-declaration@7.22.5:
|
||||
resolution: {integrity: sha512-thqK5QFghPKWLhAV321lxF95yCg2K3Ob5yw+M3VHWfdia0IkPXUtoLH8x/6Fh486QUvzhb8YOWHChTVen2/PoQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/types': 7.22.5
|
||||
dev: true
|
||||
|
||||
/@babel/helper-split-export-declaration@7.22.6:
|
||||
resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
@ -2946,7 +2927,7 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/template': 7.22.5
|
||||
'@babel/traverse': 7.22.5
|
||||
'@babel/traverse': 7.22.8
|
||||
'@babel/types': 7.22.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -2984,6 +2965,7 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@babel/types': 7.22.5
|
||||
dev: false
|
||||
|
||||
/@babel/parser@7.22.7:
|
||||
resolution: {integrity: sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q==}
|
||||
@ -5032,24 +5014,6 @@ packages:
|
||||
/@babel/traverse@7.18.13:
|
||||
resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.22.5
|
||||
'@babel/generator': 7.22.5
|
||||
'@babel/helper-environment-visitor': 7.22.5
|
||||
'@babel/helper-function-name': 7.22.5
|
||||
'@babel/helper-hoist-variables': 7.22.5
|
||||
'@babel/helper-split-export-declaration': 7.22.5
|
||||
'@babel/parser': 7.22.7
|
||||
'@babel/types': 7.22.5
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
globals: 11.12.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/@babel/traverse@7.22.5:
|
||||
resolution: {integrity: sha512-7DuIjPgERaNo6r+PZwItpjCZEa5vyw4eJGufeLxrPdBXBoLcCJCIasvK6pK/9DVNrLZTLFhUGqaC6X/PA007TQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
dependencies:
|
||||
'@babel/code-frame': 7.22.5
|
||||
'@babel/generator': 7.22.9
|
||||
@ -6028,7 +5992,7 @@ packages:
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
jest-message-util: 27.5.1
|
||||
jest-util: 27.5.1
|
||||
@ -6049,7 +6013,7 @@ packages:
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/transform': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
emittery: 0.8.1
|
||||
@ -6086,7 +6050,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/fake-timers': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
jest-mock: 27.5.1
|
||||
dev: true
|
||||
|
||||
@ -6103,7 +6067,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@sinonjs/fake-timers': 8.1.0
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
jest-message-util: 27.5.1
|
||||
jest-mock: 27.5.1
|
||||
jest-util: 27.5.1
|
||||
@ -6132,7 +6096,7 @@ packages:
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/transform': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
collect-v8-coverage: 1.0.1
|
||||
exit: 0.1.2
|
||||
@ -6245,7 +6209,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/istanbul-lib-coverage': 2.0.4
|
||||
'@types/istanbul-reports': 3.0.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/yargs': 15.0.14
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
@ -6256,7 +6220,7 @@ packages:
|
||||
dependencies:
|
||||
'@types/istanbul-lib-coverage': 2.0.4
|
||||
'@types/istanbul-reports': 3.0.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/yargs': 16.0.5
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
@ -6268,7 +6232,7 @@ packages:
|
||||
'@jest/schemas': 29.4.3
|
||||
'@types/istanbul-lib-coverage': 2.0.4
|
||||
'@types/istanbul-reports': 3.0.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/yargs': 17.0.12
|
||||
chalk: 4.1.2
|
||||
dev: true
|
||||
@ -6792,7 +6756,7 @@ packages:
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
playwright-core: 1.28.0
|
||||
dev: true
|
||||
|
||||
@ -8879,7 +8843,7 @@ packages:
|
||||
/@types/cheerio@0.22.31:
|
||||
resolution: {integrity: sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/codemirror@5.60.8:
|
||||
@ -8949,33 +8913,33 @@ packages:
|
||||
resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==}
|
||||
dependencies:
|
||||
'@types/jsonfile': 6.1.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/fs-extra@9.0.13:
|
||||
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/glob@7.2.0:
|
||||
resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==}
|
||||
dependencies:
|
||||
'@types/minimatch': 5.1.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/glob@8.0.0:
|
||||
resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==}
|
||||
dependencies:
|
||||
'@types/minimatch': 5.1.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/graceful-fs@4.1.5:
|
||||
resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/hast@2.3.4:
|
||||
@ -9047,7 +9011,7 @@ packages:
|
||||
/@types/jsdom@21.1.1:
|
||||
resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/tough-cookie': 4.0.2
|
||||
parse5: 7.1.2
|
||||
dev: true
|
||||
@ -9059,7 +9023,7 @@ packages:
|
||||
/@types/jsonfile@6.1.1:
|
||||
resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/lodash@4.14.195:
|
||||
@ -9093,7 +9057,7 @@ packages:
|
||||
/@types/node-fetch@2.6.2:
|
||||
resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
form-data: 3.0.1
|
||||
dev: true
|
||||
|
||||
@ -9142,7 +9106,7 @@ packages:
|
||||
/@types/prompts@2.4.4:
|
||||
resolution: {integrity: sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
kleur: 3.0.3
|
||||
dev: true
|
||||
|
||||
@ -9219,7 +9183,7 @@ packages:
|
||||
/@types/resolve@1.17.1:
|
||||
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/resolve@1.20.2:
|
||||
@ -9236,7 +9200,7 @@ packages:
|
||||
/@types/set-cookie-parser@2.4.2:
|
||||
resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/sinonjs__fake-timers@8.1.1:
|
||||
@ -9278,7 +9242,7 @@ packages:
|
||||
/@types/through@0.0.30:
|
||||
resolution: {integrity: sha512-FvnCJljyxhPM3gkRgWmxmDZyAQSiBQQWLI0A0VFL0K7W1oRUrPJSqNO0NvTnLkBcotdlp3lKvaT0JrnyRDkzOg==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/tough-cookie@4.0.2:
|
||||
@ -9316,7 +9280,7 @@ packages:
|
||||
/@types/webpack-sources@3.2.0:
|
||||
resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/source-list-map': 0.1.2
|
||||
source-map: 0.7.4
|
||||
dev: true
|
||||
@ -9324,7 +9288,7 @@ packages:
|
||||
/@types/webpack@4.41.32:
|
||||
resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
'@types/tapable': 1.0.8
|
||||
'@types/uglify-js': 3.17.0
|
||||
'@types/webpack-sources': 3.2.0
|
||||
@ -9339,7 +9303,7 @@ packages:
|
||||
/@types/ws@8.5.5:
|
||||
resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/@types/yargs-parser@21.0.0:
|
||||
@ -9368,7 +9332,7 @@ packages:
|
||||
resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
@ -9950,7 +9914,7 @@ packages:
|
||||
/@vue/compiler-sfc@3.2.39:
|
||||
resolution: {integrity: sha512-fqAQgFs1/BxTUZkd0Vakn3teKUt//J3c420BgnYgEOoVdTwYpBTSXCMJ88GOBCylmUBbtquGPli9tVs7LzsWIA==}
|
||||
dependencies:
|
||||
'@babel/parser': 7.22.5
|
||||
'@babel/parser': 7.22.7
|
||||
'@vue/compiler-core': 3.2.39
|
||||
'@vue/compiler-dom': 3.2.39
|
||||
'@vue/compiler-ssr': 3.2.39
|
||||
@ -11835,17 +11799,6 @@ packages:
|
||||
node-releases: 2.0.13
|
||||
update-browserslist-db: 1.0.11(browserslist@4.21.10)
|
||||
|
||||
/browserslist@4.21.3:
|
||||
resolution: {integrity: sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==}
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001518
|
||||
electron-to-chromium: 1.4.479
|
||||
node-releases: 2.0.13
|
||||
update-browserslist-db: 1.0.11(browserslist@4.21.3)
|
||||
dev: true
|
||||
|
||||
/bser@2.1.1:
|
||||
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
|
||||
dependencies:
|
||||
@ -17633,7 +17586,7 @@ packages:
|
||||
'@jest/environment': 27.5.1
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
co: 4.6.0
|
||||
dedent: 0.7.0
|
||||
@ -17769,7 +17722,7 @@ packages:
|
||||
'@jest/environment': 27.5.1
|
||||
'@jest/fake-timers': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
jest-mock: 27.5.1
|
||||
jest-util: 27.5.1
|
||||
jsdom: 16.7.0
|
||||
@ -17787,7 +17740,7 @@ packages:
|
||||
'@jest/environment': 27.5.1
|
||||
'@jest/fake-timers': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
jest-mock: 27.5.1
|
||||
jest-util: 27.5.1
|
||||
dev: true
|
||||
@ -17808,7 +17761,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 26.6.2
|
||||
'@types/graceful-fs': 4.1.5
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
anymatch: 3.1.2
|
||||
fb-watchman: 2.0.1
|
||||
graceful-fs: 4.2.10
|
||||
@ -17831,7 +17784,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@types/graceful-fs': 4.1.5
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
anymatch: 3.1.2
|
||||
fb-watchman: 2.0.1
|
||||
graceful-fs: 4.2.10
|
||||
@ -17871,7 +17824,7 @@ packages:
|
||||
'@jest/source-map': 27.5.1
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
co: 4.6.0
|
||||
expect: 27.5.1
|
||||
@ -17951,7 +17904,7 @@ packages:
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
dev: true
|
||||
|
||||
/jest-pnp-resolver@1.2.3(jest-resolve@27.5.1):
|
||||
@ -18012,7 +17965,7 @@ packages:
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/transform': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
emittery: 0.8.1
|
||||
graceful-fs: 4.2.10
|
||||
@ -18069,7 +18022,7 @@ packages:
|
||||
resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==}
|
||||
engines: {node: '>= 10.14.2'}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
graceful-fs: 4.2.10
|
||||
dev: true
|
||||
|
||||
@ -18077,7 +18030,7 @@ packages:
|
||||
resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==}
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
graceful-fs: 4.2.10
|
||||
dev: true
|
||||
|
||||
@ -18116,7 +18069,7 @@ packages:
|
||||
engines: {node: '>= 10.14.2'}
|
||||
dependencies:
|
||||
'@jest/types': 26.6.2
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
graceful-fs: 4.2.10
|
||||
is-ci: 2.0.0
|
||||
@ -18128,7 +18081,7 @@ packages:
|
||||
engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.8.0
|
||||
graceful-fs: 4.2.10
|
||||
@ -18140,7 +18093,7 @@ packages:
|
||||
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
|
||||
dependencies:
|
||||
'@jest/types': 29.0.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
chalk: 4.1.2
|
||||
ci-info: 3.8.0
|
||||
graceful-fs: 4.2.10
|
||||
@ -18165,7 +18118,7 @@ packages:
|
||||
dependencies:
|
||||
'@jest/test-result': 27.5.1
|
||||
'@jest/types': 27.5.1
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
jest-util: 27.5.1
|
||||
@ -18176,7 +18129,7 @@ packages:
|
||||
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
@ -18185,7 +18138,7 @@ packages:
|
||||
resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
dependencies:
|
||||
'@types/node': 18.16.19
|
||||
'@types/node': 20.4.6
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 8.1.1
|
||||
dev: true
|
||||
@ -23564,7 +23517,7 @@ packages:
|
||||
mime: 2.6.0
|
||||
qs: 6.11.0
|
||||
readable-stream: 3.6.0
|
||||
semver: 7.5.2
|
||||
semver: 7.5.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@ -24893,17 +24846,6 @@ packages:
|
||||
escalade: 3.1.1
|
||||
picocolors: 1.0.0
|
||||
|
||||
/update-browserslist-db@1.0.11(browserslist@4.21.3):
|
||||
resolution: {integrity: sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
browserslist: '>= 4.21.0'
|
||||
dependencies:
|
||||
browserslist: 4.21.3
|
||||
escalade: 3.1.1
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
dependencies:
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
"test": "vitest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdom": "latest",
|
||||
"vitest": "workspace:*"
|
||||
}
|
||||
}
|
||||
|
||||
0
test/vm-threads/src/external/assets/file1.png
vendored
Normal file
0
test/vm-threads/src/external/assets/file1.png
vendored
Normal file
0
test/vm-threads/src/external/assets/file2.txt
vendored
Normal file
0
test/vm-threads/src/external/assets/file2.txt
vendored
Normal file
0
test/vm-threads/src/external/assets/file3.svg
vendored
Normal file
0
test/vm-threads/src/external/assets/file3.svg
vendored
Normal file
3
test/vm-threads/src/external/css/empty.css
vendored
Normal file
3
test/vm-threads/src/external/css/empty.css
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.test1 {
|
||||
color: red;
|
||||
}
|
||||
3
test/vm-threads/src/external/css/processed.css
vendored
Normal file
3
test/vm-threads/src/external/css/processed.css
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.test2 {
|
||||
color: green;
|
||||
}
|
||||
3
test/vm-threads/src/external/css/processed.module.css
vendored
Normal file
3
test/vm-threads/src/external/css/processed.module.css
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.test3 {
|
||||
color: yellow;
|
||||
}
|
||||
43
test/vm-threads/test/import-external-css-assets.test.js
Normal file
43
test/vm-threads/test/import-external-css-assets.test.js
Normal file
@ -0,0 +1,43 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { describe, expect, test } from 'vitest'
|
||||
|
||||
import '../src/external/css/empty.css'
|
||||
import '../src/external/css/processed.css'
|
||||
|
||||
import processedModule from '../src/external/css/processed.module.css'
|
||||
|
||||
import file1 from '../src/external/assets/file1.png'
|
||||
import file2 from '../src/external/assets/file2.txt'
|
||||
import file3 from '../src/external/assets/file3.svg'
|
||||
|
||||
describe('import external css', () => {
|
||||
test('when importing empty.css, element doesn\'t change style', () => {
|
||||
const el = document.createElement('div')
|
||||
el.classList.add('test1')
|
||||
expect(el.classList.contains('test1')).toBe(true)
|
||||
expect(window.getComputedStyle(el).color).toBe('')
|
||||
})
|
||||
|
||||
test('when importing processed.css, element changes style', () => {
|
||||
const el = document.createElement('div')
|
||||
el.classList.add('test2')
|
||||
expect(el.classList.contains('test2')).toBe(true)
|
||||
expect(window.getComputedStyle(el).color).toBe('rgb(0, 128, 0)')
|
||||
})
|
||||
|
||||
test('when importing processed.module.css, element changes style', () => {
|
||||
const el = document.createElement('div')
|
||||
el.classList.add(processedModule.test3)
|
||||
expect(el.classList.contains(processedModule.test3)).toBe(true)
|
||||
expect(window.getComputedStyle(el).color).toBe('rgb(255, 255, 0)')
|
||||
})
|
||||
})
|
||||
|
||||
describe('import external assets', () => {
|
||||
test('correctly imports assets as paths', () => {
|
||||
expect(file1).toBe('/src/external/assets/file1.png')
|
||||
expect(file2).toBe('/src/external/assets/file2.txt')
|
||||
expect(file3).toBe('/src/external/assets/file3.svg')
|
||||
})
|
||||
})
|
||||
@ -3,6 +3,9 @@ import { defineConfig } from 'vitest/config'
|
||||
export default defineConfig({
|
||||
test: {
|
||||
experimentalVmThreads: true,
|
||||
css: {
|
||||
include: [/processed/],
|
||||
},
|
||||
server: {
|
||||
deps: {
|
||||
external: [/src\/external/],
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user