diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 48a0bd7773b0d7..5e00df0d89e1e0 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -63,7 +63,7 @@ module.exports = defineConfig({ 'node/no-extraneous-import': [ 'error', { - allowModules: ['vite', 'less', 'sass'] + allowModules: ['vite', 'less', 'sass', 'vitest'] } ], 'node/no-extraneous-require': [ @@ -103,7 +103,7 @@ module.exports = defineConfig({ } }, { - files: ['packages/vite/types/**'], + files: ['packages/vite/types/**', '*.spec.ts'], rules: { 'node/no-extraneous-import': 'off' } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4818124be2430f..5173da859417be 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v2 - with: - version: 6 - name: Set node version to ${{ matrix.node_version }} uses: actions/setup-node@v3 @@ -68,6 +66,9 @@ jobs: - name: Build plugin-react run: pnpm run build-plugin-react + - name: Test unit + run: pnpm run test-unit + - name: Test serve run: pnpm run test-serve -- --runInBand @@ -85,8 +86,6 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v2 - with: - version: 6 - name: Set node version to 16 uses: actions/setup-node@v3 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 621f8de145835f..40d2bb28605167 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -67,13 +67,15 @@ And re-run `pnpm install` to link the package. ## Running Tests +### Integration Tests + Each package under `packages/playground/` contains a `__tests__` directory. The tests are run using [Jest](https://jestjs.io/) + [Playwright](https://playwright.dev/) with custom integrations to make writing tests simple. The detailed setup is inside `jest.config.js` and `scripts/jest*` files. Before running the tests, make sure that [Vite has been built](#repo-setup). On Windows, you may want to [activate Developer Mode](https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development) to solve [issues with symlink creation for non-admins](https://github.com/vitejs/vite/issues/7390). Also you may want to [set git `core.symlinks` to `true` to solve issues with symlinks in git](https://github.com/vitejs/vite/issues/5242). -Each test can be run under either dev server mode or build mode. +Each integration test can be run under either dev server mode or build mode. -- `pnpm test` by default runs every test in both serve and build mode. +- `pnpm test` by default runs every integration test in both serve and build mode, and also unit tests. - `pnpm run test-serve` runs tests only under serve mode. This is just calling `jest` so you can pass any Jest flags to this command. Since Jest will attempt to run tests in parallel, if your machine has many cores this may cause flaky test failures with multiple Playwright instances running at the same time. You can force the tests to run in series with `pnpm run test-serve -- --runInBand`. @@ -83,6 +85,14 @@ Each test can be run under either dev server mode or build mode. Note package matching is not available for the `pnpm test` script, which always runs all tests. +### Unit Tests + +Other than tests under `packages/playground/` for integration tests, packages might contains unit tests under their `__tests__` directory. Unit tests are powered by [Vitest](https://vitest.dev/). The detailed config is inside `vitest.config.ts` files. + +- `pnpm run test-unit` runs unit tests under each package. + +- You can also use `pnpm run test-unit -- [match]` to run related tests. + ### Test Env and Helpers Inside playground tests, a global `page` object is automatically available, which is a Playwright [`Page`](https://playwright.dev/docs/api/class-page) instance that has already navigated to the served page of the current playground. So writing a test is as simple as: diff --git a/jest.config.ts b/jest.config.ts index 11663af4e08107..941fccbae2af36 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -3,9 +3,7 @@ import type { Config } from '@jest/types' const config: Config.InitialOptions = { preset: 'ts-jest', - testMatch: process.env.VITE_TEST_BUILD - ? ['**/playground/**/*.spec.[jt]s?(x)'] - : ['**/*.spec.[jt]s?(x)'], + testMatch: ['**/playground/**/*.spec.[jt]s?(x)'], testTimeout: process.env.CI ? 50000 : 20000, globalSetup: './scripts/jestGlobalSetup.cjs', globalTeardown: './scripts/jestGlobalTeardown.cjs', diff --git a/package.json b/package.json index 269f1bb99cb826..eae96bb7fa8dd1 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,11 @@ "preinstall": "npx only-allow pnpm", "format": "prettier --write .", "lint": "eslint packages/*/{src,types}/**", - "test": "run-s test-serve test-build", + "test": "run-s test-unit test-serve test-build", "test-serve": "jest", - "debug-serve": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest", "test-build": "cross-env VITE_TEST_BUILD=1 jest", + "test-unit": "vitest run", + "debug-serve": "cross-env VITE_DEBUG_SERVE=1 node --inspect-brk ./node_modules/.bin/jest", "debug-build": "cross-env VITE_TEST_BUILD=1 VITE_PRESERVE_BUILD_ARTIFACTS=1 node --inspect-brk ./node_modules/.bin/jest", "docs": "vitepress dev docs", "build-docs": "vitepress build docs", @@ -68,7 +69,8 @@ "ts-node": "^10.4.0", "typescript": "~4.5.4", "vite": "workspace:*", - "vitepress": "^0.22.3" + "vitepress": "^0.22.3", + "vitest": "^0.10.4" }, "simple-git-hooks": { "pre-commit": "pnpm exec lint-staged --concurrent false", diff --git a/packages/create-vite/__tests__/cli.spec.ts b/packages/create-vite/__tests__/cli.spec.ts index c52998172149e6..fbfb606f486885 100644 --- a/packages/create-vite/__tests__/cli.spec.ts +++ b/packages/create-vite/__tests__/cli.spec.ts @@ -3,6 +3,7 @@ import type { ExecaSyncReturnValue, SyncOptions } from 'execa' import { commandSync } from 'execa' import { mkdirpSync, readdirSync, remove, writeFileSync } from 'fs-extra' import { join } from 'path' +import { test, expect, beforeAll, afterEach } from 'vitest' const CLI_PATH = join(__dirname, '..') diff --git a/packages/playground/lib/__tests__/lib.spec.ts b/packages/playground/lib/__tests__/lib.spec.ts index f1e93e90d8357b..cc5887c2777fcb 100644 --- a/packages/playground/lib/__tests__/lib.spec.ts +++ b/packages/playground/lib/__tests__/lib.spec.ts @@ -35,6 +35,13 @@ if (isBuild) { ) expect(code).not.toMatch('__vitePreload') }) + + test('@import hoist', async () => { + serverLogs.forEach((log) => { + // no warning from esbuild css minifier + expect(log).not.toMatch('All "@import" rules must come first') + }) + }) } else { test('dev', async () => { expect(await page.textContent('.demo')).toBe('It works') diff --git a/packages/playground/lib/__tests__/serve.js b/packages/playground/lib/__tests__/serve.js index eac6980286af52..2534545de5c221 100644 --- a/packages/playground/lib/__tests__/serve.js +++ b/packages/playground/lib/__tests__/serve.js @@ -9,6 +9,8 @@ const { ports } = require('../../testUtils') const port = (exports.port = ports.lib) +global.serverLogs = [] + /** * @param {string} root * @param {boolean} isBuildTest @@ -16,6 +18,8 @@ const port = (exports.port = ports.lib) exports.serve = async function serve(root, isBuildTest) { // build first + setupConsoleWarnCollector() + if (!isBuildTest) { const { createServer } = require('vite') process.env.VITE_INLINE = 'inline-serve' @@ -55,7 +59,7 @@ exports.serve = async function serve(root, isBuildTest) { await build({ root, - logLevel: 'silent', + logLevel: 'warn', // output esbuild warns configFile: path.resolve(__dirname, '../vite.dyimport.config.js') }) @@ -89,3 +93,11 @@ exports.serve = async function serve(root, isBuildTest) { }) } } + +function setupConsoleWarnCollector() { + const warn = console.warn + console.warn = (...args) => { + global.serverLogs.push(args.join(' ')) + return warn.call(console, ...args) + } +} diff --git a/packages/playground/lib/src/dynamic.css b/packages/playground/lib/src/dynamic.css new file mode 100644 index 00000000000000..4378c8d328cfbe --- /dev/null +++ b/packages/playground/lib/src/dynamic.css @@ -0,0 +1,4 @@ +@import 'https://cdn.jsdelivr.net/npm/@mdi/font@5.9.55/css/materialdesignicons.min.css'; +.dynamic { + color: red; +} diff --git a/packages/playground/lib/src/index.css b/packages/playground/lib/src/index.css new file mode 100644 index 00000000000000..b0bd670bd9ecad --- /dev/null +++ b/packages/playground/lib/src/index.css @@ -0,0 +1,3 @@ +.index { + color: blue; +} diff --git a/packages/playground/lib/src/main2.js b/packages/playground/lib/src/main2.js index 0c729fad8d165c..f19a16bb128949 100644 --- a/packages/playground/lib/src/main2.js +++ b/packages/playground/lib/src/main2.js @@ -1,4 +1,9 @@ +import './index.css' + export default async function message(sel) { const message = await import('./message.js') + + await import('./dynamic.css') + document.querySelector(sel).textContent = message.default } diff --git a/packages/playground/lib/vite.dyimport.config.js b/packages/playground/lib/vite.dyimport.config.js index 76311f4b8ba138..d738503f0c9d09 100644 --- a/packages/playground/lib/vite.dyimport.config.js +++ b/packages/playground/lib/vite.dyimport.config.js @@ -6,7 +6,6 @@ const path = require('path') */ module.exports = { build: { - minify: false, lib: { entry: path.resolve(__dirname, 'src/main2.js'), formats: ['es'], diff --git a/packages/plugin-react/src/jsx-runtime/babel-restore-jsx.spec.ts b/packages/plugin-react/src/jsx-runtime/babel-restore-jsx.spec.ts index 59d6661bedd11b..391007f68c1329 100644 --- a/packages/plugin-react/src/jsx-runtime/babel-restore-jsx.spec.ts +++ b/packages/plugin-react/src/jsx-runtime/babel-restore-jsx.spec.ts @@ -1,5 +1,6 @@ import babelRestoreJSX from './babel-restore-jsx' import * as babel from '@babel/core' +import { describe, it, expect } from 'vitest' function jsx(code: string) { return babel.transform(code, { diff --git a/packages/plugin-react/src/jsx-runtime/restore-jsx.spec.ts b/packages/plugin-react/src/jsx-runtime/restore-jsx.spec.ts index c216e99bc3480d..4f6a34ee60d915 100644 --- a/packages/plugin-react/src/jsx-runtime/restore-jsx.spec.ts +++ b/packages/plugin-react/src/jsx-runtime/restore-jsx.spec.ts @@ -1,5 +1,6 @@ import { restoreJSX } from './restore-jsx' import * as babel from '@babel/core' +import { describe, it, expect } from 'vitest' async function jsx(sourceCode: string) { const [ast] = await restoreJSX(babel, sourceCode, 'test.js') diff --git a/packages/plugin-vue/src/template.ts b/packages/plugin-vue/src/template.ts index 72e9588967556e..c7eed9015d6339 100644 --- a/packages/plugin-vue/src/template.ts +++ b/packages/plugin-vue/src/template.ts @@ -139,7 +139,7 @@ export function resolveTemplateCompilerOptions( tags: transformAssetUrls as any } } else { - transformAssetUrls = { ...transformAssetUrls, ...assetUrlOptions } + transformAssetUrls = { ...assetUrlOptions, ...transformAssetUrls } } } else { transformAssetUrls = assetUrlOptions diff --git a/packages/vite/LICENSE.md b/packages/vite/LICENSE.md index 30803708e30a76..80feb7f95c6941 100644 --- a/packages/vite/LICENSE.md +++ b/packages/vite/LICENSE.md @@ -3465,6 +3465,35 @@ Repository: chalk/strip-ansi --------------------------------------- +## strip-literal +License: MIT +By: Anthony Fu +Repository: git+https://github.com/antfu/strip-literal.git + +> MIT License +> +> Copyright (c) 2022 Anthony Fu +> +> Permission is hereby granted, free of charge, to any person obtaining a copy +> of this software and associated documentation files (the "Software"), to deal +> in the Software without restriction, including without limitation the rights +> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +> copies of the Software, and to permit persons to whom the Software is +> furnished to do so, subject to the following conditions: +> +> The above copyright notice and this permission notice shall be included in all +> copies or substantial portions of the Software. +> +> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +> SOFTWARE. + +--------------------------------------- + ## to-regex-range License: MIT By: Jon Schlinkert, Rouven Weßling diff --git a/packages/vite/package.json b/packages/vite/package.json index 55c86878622111..b508842619033e 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -112,6 +112,7 @@ "source-map-js": "^1.0.2", "source-map-support": "^0.5.21", "strip-ansi": "^6.0.1", + "strip-literal": "^0.2.0", "terser": "^5.13.1", "tsconfck": "^1.2.2", "tslib": "^2.4.0", diff --git a/packages/vite/src/node/__tests__/asset.spec.ts b/packages/vite/src/node/__tests__/asset.spec.ts index 6e6b969bcbd38c..8727aa6485eb26 100644 --- a/packages/vite/src/node/__tests__/asset.spec.ts +++ b/packages/vite/src/node/__tests__/asset.spec.ts @@ -1,3 +1,4 @@ +import { describe, test, expect } from 'vitest' import { assetFileNamesToFileName, getAssetHash } from '../plugins/asset' describe('getAssetHash', () => { diff --git a/packages/vite/src/node/__tests__/build.spec.ts b/packages/vite/src/node/__tests__/build.spec.ts index 578e3a4c68ff8d..b49847f1d955a4 100644 --- a/packages/vite/src/node/__tests__/build.spec.ts +++ b/packages/vite/src/node/__tests__/build.spec.ts @@ -1,6 +1,7 @@ import type { LibraryFormats, LibraryOptions } from '../build' import { resolveLibFilename } from '../build' import { resolve } from 'path' +import { describe, test, expect } from 'vitest' type FormatsToFileNames = [LibraryFormats, string][] const baseLibOptions: LibraryOptions = { diff --git a/packages/vite/src/node/__tests__/cleanString.spec.ts b/packages/vite/src/node/__tests__/cleanString.spec.ts deleted file mode 100644 index f307c4816b7cd3..00000000000000 --- a/packages/vite/src/node/__tests__/cleanString.spec.ts +++ /dev/null @@ -1,190 +0,0 @@ -import { assetAttrsConfig } from './../plugins/html' -import { emptyString } from '../../node/cleanString' - -test('comments', () => { - expect( - emptyString(` - // comment1 // comment - // comment1 - /* coment2 */ - /* - // coment3 - */ - /* // coment3 */ - /* // coment3 */ // comment - // comment 4 /* comment 5 */ - `).trim() - ).toBe('') -}) - -test('strings', () => { - const clean = emptyString(` - // comment1 - const a = 'aaaa' - /* coment2 */ - const b = "bbbb" - /* - // coment3 - */ - /* // coment3 */ - // comment 4 /* comment 5 */ - `) - expect(clean).toMatch("const a = '\0\0\0\0'") - expect(clean).toMatch('const b = "\0\0\0\0"') -}) - -test('escape character', () => { - const clean = emptyString(` - '1\\'1' - "1\\"1" - "1\\"1\\"1" - "1\\'1'\\"1" - "1'1'" - "1'\\'1\\''\\"1\\"\\"" - '1"\\"1\\""\\"1\\"\\"' - '""1""' - '"""1"""' - '""""1""""' - "''1''" - "'''1'''" - "''''1''''" - `) - expect(clean).not.toMatch('1') -}) - -test('regexp affect', () => { - const clean = emptyString(` - /'/ - '1' - /"/ - "1" - `) - expect(clean).not.toMatch('1') -}) - -test('strings comment nested', () => { - expect( - emptyString(` - // comment 1 /* " */ - const a = "a //" - // comment 2 /* " */ - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - // comment 1 /* ' */ - const a = "a //" - // comment 2 /* ' */ - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - // comment 1 /* \` */ - const a = "a //" - // comment 2 /* \` */ - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - const a = "a //" - console.log("console") - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - const a = "a /*" - console.log("console") - const b = "b */" - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - const a = "a ' " - console.log("console") - const b = "b ' " - `) - ).toMatch('const a = "\0\0\0\0"') - - expect( - emptyString(` - const a = "a \` " - console.log("console") - const b = "b \` " - `) - ).toMatch('const a = "\0\0\0\0"') -}) - -test('find empty string flag in raw index', () => { - const str = ` - const a = "aaaaa" - const b = "bbbbb" - ` - const clean = emptyString(str) - expect(clean).toMatch('const a = "\0\0\0\0\0"') - expect(clean).toMatch('const b = "\0\0\0\0\0"') - - const aIndex = str.indexOf('const a = "aaaaa"') - const aStart = clean.indexOf('\0\0\0\0\0', aIndex) - expect(str.slice(aStart, aStart + 5)).toMatch('aaaaa') - - const bIndex = str.indexOf('const b = "bbbbb"') - const bStart = clean.indexOf('\0\0\0\0\0', bIndex) - expect(str.slice(bStart, bStart + 5)).toMatch('bbbbb') -}) - -test('template string nested', () => { - let str = '`aaaa`' - let res = '`\0\0\0\0`' - let clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aaaa` `aaaa`' - res = '`\0\0\0\0` `\0\0\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aa${a}aa`' - res = '`\0\0${a}\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aa${a + `a` + a}aa`' - res = '`\0\0${a + `\0` + a}\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aa${a + `a` + a}aa` `aa${a + `a` + a}aa`' - res = '`\0\0${a + `\0` + a}\0\0` `\0\0${a + `\0` + a}\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aa${a + `aaaa${c + (a = {b: 1}) + d}` + a}aa`' - res = '`\0\0${a + `\0\0\0\0${c + (a = {b: 1}) + d}` + a}\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = - '`aa${a + `aaaa${c + (a = {b: 1}) + d}` + a}aa` `aa${a + `aaaa${c + (a = {b: 1}) + d}` + a}aa`' - res = - '`\0\0${a + `\0\0\0\0${c + (a = {b: 1}) + d}` + a}\0\0` `\0\0${a + `\0\0\0\0${c + (a = {b: 1}) + d}` + a}\0\0`' - clean = emptyString(str) - expect(clean).toMatch(res) - - str = '`aaaa' - res = '' - try { - clean = emptyString(str) - } catch {} - expect(clean).toMatch(res) - - str = - "" - res = `` - clean = emptyString(str) - expect(clean).toMatch(res) -}) diff --git a/packages/vite/src/node/__tests__/config.spec.ts b/packages/vite/src/node/__tests__/config.spec.ts index d5e6514392b852..83995ab28adcbd 100644 --- a/packages/vite/src/node/__tests__/config.spec.ts +++ b/packages/vite/src/node/__tests__/config.spec.ts @@ -1,6 +1,7 @@ import type { InlineConfig } from '..' import type { UserConfigExport, UserConfig } from '../config' import { mergeConfig, resolveConfig, resolveEnvPrefix } from '../config' +import { describe, test, expect } from 'vitest' describe('mergeConfig', () => { test('handles configs with different alias schemas', () => { diff --git a/packages/vite/src/node/__tests__/dev.spec.ts b/packages/vite/src/node/__tests__/dev.spec.ts index 3eefd7b4b903c1..cdb0fc123f4b4f 100644 --- a/packages/vite/src/node/__tests__/dev.spec.ts +++ b/packages/vite/src/node/__tests__/dev.spec.ts @@ -1,4 +1,5 @@ import { resolveConfig } from '..' +import { describe, test, expect } from 'vitest' describe('resolveBuildOptions in dev', () => { test('build.rollupOptions should not have input in lib', async () => { diff --git a/packages/vite/src/node/__tests__/plugins/css.spec.ts b/packages/vite/src/node/__tests__/plugins/css.spec.ts index e0d1f04a6510b2..eeacaf482b0c31 100644 --- a/packages/vite/src/node/__tests__/plugins/css.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/css.spec.ts @@ -2,6 +2,7 @@ import { cssUrlRE, cssPlugin, hoistAtRules } from '../../plugins/css' import { resolveConfig } from '../../config' import fs from 'fs' import path from 'path' +import { describe, vi, test, expect } from 'vitest' describe('search css url function', () => { test('some spaces before it', () => { @@ -69,7 +70,7 @@ describe('css path resolutions', () => { await buildStart.call({}) - const mockFs = jest + const mockFs = vi .spyOn(fs, 'readFile') // @ts-ignore jest.spyOn not recognize overrided `fs.readFile` definition. .mockImplementationOnce((p, encoding, callback) => { diff --git a/packages/vite/src/node/__tests__/plugins/define.spec.ts b/packages/vite/src/node/__tests__/plugins/define.spec.ts index 9a65f8f3a51cea..b9acc81cb790d5 100644 --- a/packages/vite/src/node/__tests__/plugins/define.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/define.spec.ts @@ -1,3 +1,4 @@ +import { describe, test, expect } from 'vitest' import { definePlugin } from '../../plugins/define' import { resolveConfig } from '../../config' diff --git a/packages/vite/src/node/__tests__/plugins/import.spec.ts b/packages/vite/src/node/__tests__/plugins/import.spec.ts index f0341e81b50f3c..e232702d57d354 100644 --- a/packages/vite/src/node/__tests__/plugins/import.spec.ts +++ b/packages/vite/src/node/__tests__/plugins/import.spec.ts @@ -1,3 +1,4 @@ +import { describe, test, expect } from 'vitest' import { transformCjsImport } from '../../plugins/importAnalysis' describe('transformCjsImport', () => { diff --git a/packages/vite/src/node/__tests__/scan.spec.ts b/packages/vite/src/node/__tests__/scan.spec.ts index db11bcc45b284c..8d5a275fca0292 100644 --- a/packages/vite/src/node/__tests__/scan.spec.ts +++ b/packages/vite/src/node/__tests__/scan.spec.ts @@ -1,5 +1,6 @@ import { scriptRE, commentRE, importsRE } from '../optimizer/scan' import { multilineCommentsRE, singlelineCommentsRE } from '../utils' +import { describe, test, expect } from 'vitest' describe('optimizer-scan:script-test', () => { const scriptContent = `import { defineComponent } from 'vue' diff --git a/packages/vite/src/node/__tests__/utils.spec.ts b/packages/vite/src/node/__tests__/utils.spec.ts index 1162105c3f19c7..29fd53f3c9a32e 100644 --- a/packages/vite/src/node/__tests__/utils.spec.ts +++ b/packages/vite/src/node/__tests__/utils.spec.ts @@ -4,6 +4,7 @@ import { isWindows, resolveHostname } from '../utils' +import { describe, test, expect } from 'vitest' describe('injectQuery', () => { if (isWindows) { diff --git a/packages/vite/src/node/cleanString.ts b/packages/vite/src/node/cleanString.ts deleted file mode 100644 index 9b9ef656f4e017..00000000000000 --- a/packages/vite/src/node/cleanString.ts +++ /dev/null @@ -1,142 +0,0 @@ -import type { RollupError } from 'rollup' -import { multilineCommentsRE, singlelineCommentsRE } from './utils' - -// bank on the non-overlapping nature of regex matches and combine all filters into one giant regex -// /`([^`\$\{\}]|\$\{(`|\g<1>)*\})*`/g can match nested string template -// but js not support match expression(\g<0>). so clean string template(`...`) in other ways. -const stringsRE = /"([^"\r\n]|(?<=\\)")*"|'([^'\r\n]|(?<=\\)')*'/g -const cleanerRE = new RegExp( - `${stringsRE.source}|${multilineCommentsRE.source}|${singlelineCommentsRE.source}`, - 'g' -) - -const blankReplacer = (s: string) => ' '.repeat(s.length) -const stringBlankReplacer = (s: string) => - `${s[0]}${'\0'.repeat(s.length - 2)}${s[0]}` - -export function emptyString(raw: string): string { - let res = raw.replace(cleanerRE, (s: string) => - s[0] === '/' ? blankReplacer(s) : stringBlankReplacer(s) - ) - - let lastEnd = 0 - let start = 0 - while ((start = res.indexOf('`', lastEnd)) >= 0) { - let clean - ;[clean, lastEnd] = lexStringTemplateExpression(res, start) - res = replaceAt(res, start, lastEnd, clean) - } - - return res -} - -export function emptyCssComments(raw: string) { - return raw.replace(multilineCommentsRE, blankReplacer) -} - -const enum LexerState { - // template string - inTemplateString, - inInterpolationExpression, - inObjectExpression, - // strings - inSingleQuoteString, - inDoubleQuoteString, - // comments - inMultilineCommentsRE, - inSinglelineCommentsRE -} - -function replaceAt( - string: string, - start: number, - end: number, - replacement: string -): string { - return string.slice(0, start) + replacement + string.slice(end) -} - -/** - * lex string template and clean it. - */ -function lexStringTemplateExpression( - code: string, - start: number -): [string, number] { - let state = LexerState.inTemplateString as LexerState - let clean = '`' - const opStack: LexerState[] = [state] - - function pushStack(newState: LexerState) { - state = newState - opStack.push(state) - } - - function popStack() { - opStack.pop() - state = opStack[opStack.length - 1] - } - - let i = start + 1 - outer: for (; i < code.length; i++) { - const char = code.charAt(i) - switch (state) { - case LexerState.inTemplateString: - if (char === '$' && code.charAt(i + 1) === '{') { - pushStack(LexerState.inInterpolationExpression) - clean += '${' - i++ // jump next - } else if (char === '`') { - popStack() - clean += char - if (opStack.length === 0) { - break outer - } - } else { - clean += '\0' - } - break - case LexerState.inInterpolationExpression: - if (char === '{') { - pushStack(LexerState.inObjectExpression) - clean += char - } else if (char === '}') { - popStack() - clean += char - } else if (char === '`') { - pushStack(LexerState.inTemplateString) - clean += char - } else { - clean += char - } - break - case LexerState.inObjectExpression: - if (char === '}') { - popStack() - clean += char - } else if (char === '`') { - pushStack(LexerState.inTemplateString) - clean += char - } else { - clean += char - } - break - default: - throw new Error('unknown string template lexer state') - } - } - - if (opStack.length !== 0) { - error(start) - } - - return [clean, i + 1] -} - -function error(pos: number) { - const err = new Error( - `can not match string template expression.` - ) as RollupError - err.pos = pos - throw err -} diff --git a/packages/vite/src/node/plugins/assetImportMetaUrl.ts b/packages/vite/src/node/plugins/assetImportMetaUrl.ts index b8c16f76d2b93f..217b0d3fee1564 100644 --- a/packages/vite/src/node/plugins/assetImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/assetImportMetaUrl.ts @@ -3,7 +3,7 @@ import MagicString from 'magic-string' import path from 'path' import { fileToUrl } from './asset' import type { ResolvedConfig } from '../config' -import { emptyString } from '../cleanString' +import { stripLiteral } from 'strip-literal' /** * Convert `new URL('./foo.png', import.meta.url)` to its resolved built URL @@ -27,7 +27,7 @@ export function assetImportMetaUrlPlugin(config: ResolvedConfig): Plugin { let s: MagicString | undefined const assetImportMetaUrlRE = /\bnew\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*,?\s*\)/g - const cleanString = emptyString(code) + const cleanString = stripLiteral(code) let match: RegExpExecArray | null while ((match = assetImportMetaUrlRE.exec(cleanString))) { diff --git a/packages/vite/src/node/plugins/css.ts b/packages/vite/src/node/plugins/css.ts index cd57acd1690902..22dfc33f67a509 100644 --- a/packages/vite/src/node/plugins/css.ts +++ b/packages/vite/src/node/plugins/css.ts @@ -49,7 +49,7 @@ import { transform, formatMessages } from 'esbuild' import { addToHTMLProxyTransformResult } from './html' import { injectSourcesContent, getCodeWithSourcemap } from '../server/sourcemap' import type { RawSourceMap } from '@ampproject/remapping' -import { emptyCssComments } from '../cleanString' +import { emptyCssComments } from '../utils' // const debug = createDebugger('vite:css') @@ -443,13 +443,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { } }) // only external @imports and @charset should exist at this point - // hoist them to the top of the CSS chunk per spec (#1845 and #6333) - if (css.includes('@import') || css.includes('@charset')) { - css = await hoistAtRules(css) - } - if (minify && config.build.minify) { - css = await minifyCSS(css, config) - } + css = await finalizeCss(css, minify, config) return css } @@ -559,10 +553,7 @@ export function cssPostPlugin(config: ResolvedConfig): Plugin { let extractedCss = outputToExtractedCSSMap.get(opts) if (extractedCss && !hasEmitted) { hasEmitted = true - // minify css - if (config.build.minify) { - extractedCss = await minifyCSS(extractedCss, config) - } + extractedCss = await finalizeCss(extractedCss, true, config) this.emitFile({ name: 'style.css', type: 'asset', @@ -922,6 +913,21 @@ function combineSourcemapsIfExists( : map1 } +async function finalizeCss( + css: string, + minify: boolean, + config: ResolvedConfig +) { + // hoist external @imports and @charset to the top of the CSS chunk per spec (#1845 and #6333) + if (css.includes('@import') || css.includes('@charset')) { + css = await hoistAtRules(css) + } + if (minify && config.build.minify) { + css = await minifyCSS(css, config) + } + return css +} + interface PostCSSConfigResult { options: PostCSS.ProcessOptions plugins: PostCSS.Plugin[] diff --git a/packages/vite/src/node/plugins/html.ts b/packages/vite/src/node/plugins/html.ts index 0223c351af6071..6d793c416ce60a 100644 --- a/packages/vite/src/node/plugins/html.ts +++ b/packages/vite/src/node/plugins/html.ts @@ -36,7 +36,7 @@ import type { TextNode } from '@vue/compiler-dom' import { NodeTypes } from '@vue/compiler-dom' -import { emptyString } from '../cleanString' +import { stripLiteral } from 'strip-literal' interface ScriptAssetsUrl { start: number @@ -308,7 +308,7 @@ export function buildHtmlPlugin(config: ResolvedConfig): Plugin { } } else if (node.children.length) { const scriptNode = node.children.pop()! as TextNode - const cleanCode = emptyString(scriptNode.content) + const cleanCode = stripLiteral(scriptNode.content) let match: RegExpExecArray | null while ((match = inlineImportRE.exec(cleanCode))) { diff --git a/packages/vite/src/node/plugins/workerImportMetaUrl.ts b/packages/vite/src/node/plugins/workerImportMetaUrl.ts index 3d8970b746349c..bfd8c22dcad372 100644 --- a/packages/vite/src/node/plugins/workerImportMetaUrl.ts +++ b/packages/vite/src/node/plugins/workerImportMetaUrl.ts @@ -10,7 +10,7 @@ import { ENV_ENTRY, ENV_PUBLIC_PATH } from '../constants' import MagicString from 'magic-string' import type { ViteDevServer } from '..' import type { RollupError } from 'rollup' -import { emptyString } from '../cleanString' +import { stripLiteral } from 'strip-literal' type WorkerType = 'classic' | 'module' | 'ignore' const ignoreFlagRE = /\/\*\s*@vite-ignore\s*\*\// @@ -110,7 +110,7 @@ export function workerImportMetaUrlPlugin(config: ResolvedConfig): Plugin { code.includes('new URL') && code.includes(`import.meta.url`) ) { - const cleanString = emptyString(code) + const cleanString = stripLiteral(code) const workerImportMetaUrlRE = /\bnew\s+(Worker|SharedWorker)\s*\(\s*(new\s+URL\s*\(\s*('[^']+'|"[^"]+"|`[^`]+`)\s*,\s*import\.meta\.url\s*\))/g diff --git a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts index 9fbd07e90aa089..ab0555ae7982e9 100644 --- a/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts +++ b/packages/vite/src/node/server/__tests__/pluginContainer.spec.ts @@ -4,6 +4,7 @@ import type { Plugin } from '../../plugin' import { ModuleGraph } from '../moduleGraph' import type { PluginContainer } from '../pluginContainer' import { createPluginContainer } from '../pluginContainer' +import { describe, it, expect, beforeEach } from 'vitest' let resolveId: (id: string) => any let moduleGraph: ModuleGraph diff --git a/packages/vite/src/node/server/__tests__/search-root.spec.ts b/packages/vite/src/node/server/__tests__/search-root.spec.ts index 7322768286809e..ff9366e8791534 100644 --- a/packages/vite/src/node/server/__tests__/search-root.spec.ts +++ b/packages/vite/src/node/server/__tests__/search-root.spec.ts @@ -1,5 +1,6 @@ import { searchForWorkspaceRoot } from '../searchRoot' import { resolve } from 'path' +import { describe, test, expect } from 'vitest' describe('searchForWorkspaceRoot', () => { test('lerna', () => { diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index 8d33554706dee2..8eca99268e93d7 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -294,6 +294,7 @@ function invalidate(mod: ModuleNode, timestamp: number, seen: Set) { mod.lastHMRTimestamp = timestamp mod.transformResult = null mod.ssrModule = null + mod.ssrError = null mod.ssrTransformResult = null mod.importers.forEach((importer) => { if (!importer.acceptedHmrDeps.has(mod)) { diff --git a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts index ad16534b088e2b..5fb51093405250 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrExternal.spec.ts @@ -1,4 +1,5 @@ import { stripNesting } from '../ssrExternal' +import { test, expect } from 'vitest' test('stripNesting', async () => { expect(stripNesting(['c', 'p1>c1', 'p2 > c2'])).toEqual(['c', 'c1', 'c2']) diff --git a/packages/vite/src/node/ssr/__tests__/ssrModuleLoader.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrModuleLoader.spec.ts index 6a45a2b70509d0..93a04734840d31 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrModuleLoader.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrModuleLoader.spec.ts @@ -1,12 +1,13 @@ import { resolve } from 'path' import { createServer } from '../../index' +import { test, vi, expect } from 'vitest' const badjs = resolve(__dirname, './fixtures/ssrModuleLoader-bad.js') const THROW_MESSAGE = 'it is an expected error' test('always throw error when evaluating an wrong SSR module', async () => { const viteServer = await createServer() - const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const spy = vi.spyOn(console, 'error').mockImplementation(() => {}) const expectedErrors = [] for (const i of [0, 1]) { try { diff --git a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts index 0e9181214c2b82..9c1fdea5939793 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts @@ -1,6 +1,7 @@ import { transformWithEsbuild } from '../../plugins/esbuild' import { traverseHtml } from '../../plugins/html' import { ssrTransform } from '../ssrTransform' +import { test, expect } from 'vitest' test('default import', async () => { expect( diff --git a/packages/vite/src/node/utils.ts b/packages/vite/src/node/utils.ts index d41dd6850ebb56..ddcaced9832bc1 100644 --- a/packages/vite/src/node/utils.ts +++ b/packages/vite/src/node/utils.ts @@ -775,8 +775,8 @@ function gracefulRename( ) { setTimeout(function () { fs.stat(to, function (stater, st) { - if (stater && stater.code === 'ENOENT') gracefulRename(from, to, CB) - else cb(er) + if (stater && stater.code === 'ENOENT') fs.rename(from, to, CB) + else CB(er) }) }, backoff) if (backoff < 100) backoff += 10 @@ -785,3 +785,7 @@ function gracefulRename( if (cb) cb(er) }) } + +export function emptyCssComments(raw: string) { + return raw.replace(multilineCommentsRE, (s) => ' '.repeat(s.length)) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d3aea697843c5b..a20eb4e3bb7d1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,6 +45,7 @@ importers: typescript: ~4.5.4 vite: workspace:* vitepress: ^0.22.3 + vitest: ^0.10.4 devDependencies: '@microsoft/api-extractor': 7.23.0 '@types/fs-extra': 9.0.13 @@ -81,6 +82,7 @@ importers: typescript: 4.5.4 vite: link:packages/vite vitepress: 0.22.3 + vitest: 0.10.4 packages/create-vite: specifiers: @@ -891,6 +893,7 @@ importers: source-map-js: ^1.0.2 source-map-support: ^0.5.21 strip-ansi: ^6.0.1 + strip-literal: ^0.2.0 terser: ^5.13.1 tsconfck: ^1.2.2 tslib: ^2.4.0 @@ -964,6 +967,7 @@ importers: source-map-js: 1.0.2 source-map-support: 0.5.21 strip-ansi: 6.0.1 + strip-literal: 0.2.0 terser: 5.13.1 tsconfck: 1.2.2_typescript@4.5.4 tslib: 2.4.0 @@ -2579,6 +2583,16 @@ packages: resolution: {integrity: sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ==} dev: true + /@types/chai-subset/1.3.3: + resolution: {integrity: sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==} + dependencies: + '@types/chai': 4.3.1 + dev: true + + /@types/chai/4.3.1: + resolution: {integrity: sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==} + dev: true + /@types/convert-source-map/1.5.2: resolution: {integrity: sha512-tHs++ZeXer40kCF2JpE51Hg7t4HPa18B1b1Dzy96S0eCw8QKECNMYMfwa1edK/x8yCN0r4e6ewvLcc5CsVGkdg==} dev: true @@ -3370,6 +3384,10 @@ packages: resolution: {integrity: sha512-TaTivMB6pYI1kXwrFlEhLeGfOqoDNdTxjCdwRfFFkEA30Eu+k48W34nlok2EYWJfFFzqaEmichdNM7th6M5HNw==} dev: true + /assertion-error/1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + dev: true + /astral-regex/2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -3666,6 +3684,19 @@ packages: resolution: {integrity: sha512-kbaCEBRRVSoeNs74sCuq92MJyGrMtjWVfhltoHUCW4t4pXFvGjUBrfo47weBRViHkiV3eBYyIsfl956NtHGazw==} dev: false + /chai/4.3.6: + resolution: {integrity: sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==} + engines: {node: '>=4'} + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.2 + deep-eql: 3.0.1 + get-func-name: 2.0.0 + loupe: 2.3.4 + pathval: 1.1.1 + type-detect: 4.0.8 + dev: true + /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -3692,6 +3723,10 @@ packages: is-regex: 1.1.4 dev: true + /check-error/1.0.2: + resolution: {integrity: sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=} + dev: true + /chokidar/3.5.2: resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==} engines: {node: '>= 8.10.0'} @@ -4374,6 +4409,13 @@ packages: resolution: {integrity: sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=} dev: true + /deep-eql/3.0.1: + resolution: {integrity: sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==} + engines: {node: '>=0.12'} + dependencies: + type-detect: 4.0.8 + dev: true + /deep-is/0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -5356,6 +5398,10 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true + /get-func-name/2.0.0: + resolution: {integrity: sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=} + dev: true + /get-intrinsic/1.1.1: resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==} dependencies: @@ -6786,6 +6832,11 @@ packages: engines: {node: '>= 12.13.0'} dev: true + /local-pkg/0.4.1: + resolution: {integrity: sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==} + engines: {node: '>=14'} + dev: true + /locate-path/2.0.0: resolution: {integrity: sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=} engines: {node: '>=4'} @@ -6869,6 +6920,12 @@ packages: js-tokens: 4.0.0 dev: false + /loupe/2.3.4: + resolution: {integrity: sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==} + dependencies: + get-func-name: 2.0.0 + dev: true + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -7560,6 +7617,10 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + /pathval/1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + dev: true + /pend/1.2.0: resolution: {integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=} dev: true @@ -8957,6 +9018,12 @@ packages: engines: {node: '>=8'} dev: true + /strip-literal/0.2.0: + resolution: {integrity: sha512-pqhiiFRDifA2CRVH0Gmv6MDbd2b27MS0oIqqy7JCqfL5m2sh68223lmEK2eoBXp4vNaq8G1Wzwd9dfQcWszUlg==} + dependencies: + acorn: 8.7.1 + dev: true + /stylis/4.0.13: resolution: {integrity: sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==} @@ -9242,6 +9309,16 @@ packages: resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} dev: false + /tinypool/0.1.3: + resolution: {integrity: sha512-2IfcQh7CP46XGWGGbdyO4pjcKqsmVqFAPcXfPxcPXmOWt9cYkTP9HcDmGgsfijYoAEc4z9qcpM/BaBz46Y9/CQ==} + engines: {node: '>=14.0.0'} + dev: true + + /tinyspy/0.3.2: + resolution: {integrity: sha512-2+40EP4D3sFYy42UkgkFFB+kiX2Tg3URG/lVvAZFfLxgGpnWl5qQJuBw1gaLttq8UOS+2p3C0WrhJnQigLTT2Q==} + engines: {node: '>=14.0.0'} + dev: true + /tmp/0.2.1: resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} engines: {node: '>=8.17.0'} @@ -9623,6 +9700,34 @@ packages: - react-dom dev: true + /vitest/0.10.4: + resolution: {integrity: sha512-FJ2av2PVozmyz9nqHRoC3H8j2z0OQXj8P8jS5oyMY9mfPWB06GS5k/1Ot++TkVBLQRHZCcVzjbK4BO7zqAJZGQ==} + engines: {node: '>=v14.16.0'} + hasBin: true + peerDependencies: + '@vitest/ui': '*' + c8: '*' + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@vitest/ui': + optional: true + c8: + optional: true + happy-dom: + optional: true + jsdom: + optional: true + dependencies: + '@types/chai': 4.3.1 + '@types/chai-subset': 1.3.3 + chai: 4.3.6 + local-pkg: 0.4.1 + tinypool: 0.1.3 + tinyspy: 0.3.2 + vite: link:packages/vite + dev: true + /void-elements/3.1.0: resolution: {integrity: sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=} engines: {node: '>=0.10.0'} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 00000000000000..78e54e98cc02d9 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from 'vitest/config' + +export default defineConfig({ + test: { + exclude: [ + '**/node_modules/**', + '**/dist/**', + './packages/playground/**/*.*', + './packages/temp/**/*.*' + ] + }, + esbuild: { + target: 'node14' + } +})