Skip to content

Commit

Permalink
fix(scan): handle local scripts with lang=ts (#5850)
Browse files Browse the repository at this point in the history
  • Loading branch information
bluwy authored Dec 1, 2021
1 parent 08a1ec7 commit 7ed8702
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 30 deletions.
12 changes: 10 additions & 2 deletions packages/playground/vue/__tests__/vue.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,16 @@ test(':slotted', async () => {
expect(await getColor('.slotted')).toBe('red')
})

test('scan deps from <script setup lang="ts">', async () => {
expect(await page.textContent('.scan')).toBe('ok')
describe('dep scan', () => {
test('scan deps from <script setup lang="ts">', async () => {
expect(await page.textContent('.scan')).toBe('ok')
})

test('find deps on initial scan', () => {
serverLogs.forEach((log) => {
expect(log).not.toMatch('new dependencies found')
})
})
})

describe('pre-processors', () => {
Expand Down
62 changes: 37 additions & 25 deletions packages/vite/src/node/optimizer/scan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,42 +273,29 @@ function esbuildScanPlugin(
contextMatch &&
(contextMatch[1] || contextMatch[2] || contextMatch[3])
if (
(path.endsWith('.vue') && setupRE.test(raw)) ||
(path.endsWith('.vue') && setupRE.test(openTag)) ||
(path.endsWith('.svelte') && context !== 'module')
) {
// append imports in TS to prevent esbuild from removing them
// since they may be used in the template
const localContent =
content +
(loader.startsWith('ts') ? extractImportPaths(content) : '')
localScripts[path] = {
loader,
contents: content
contents: localContent
}
js += `import '${virtualModulePrefix}${path}';\n`
} else {
js += content + '\n'
}
}
}
// empty singleline & multiline comments to avoid matching comments
const code = js
.replace(multilineCommentsRE, '/* */')
.replace(singlelineCommentsRE, '')

if (
loader.startsWith('ts') &&
(path.endsWith('.svelte') ||
(path.endsWith('.vue') && setupRE.test(raw)))
) {
// when using TS + (Vue + <script setup>) or Svelte, imports may seem
// unused to esbuild and dropped in the build output, which prevents
// esbuild from crawling further.
// the solution is to add `import 'x'` for every source to force
// esbuild to keep crawling due to potential side effects.
let m
while ((m = importsRE.exec(code)) != null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === importsRE.lastIndex) {
importsRE.lastIndex++
}
js += `\nimport ${m[1]}`
}

// `<script>` in Svelte has imports that can be used in the template
// so we handle them here too
if (loader.startsWith('ts') && path.endsWith('.svelte')) {
js += extractImportPaths(js)
}

// This will trigger incorrectly if `export default` is contained
Expand Down Expand Up @@ -488,6 +475,31 @@ async function transformGlob(
return s.toString()
}

/**
* when using TS + (Vue + `<script setup>`) or Svelte, imports may seem
* unused to esbuild and dropped in the build output, which prevents
* esbuild from crawling further.
* the solution is to add `import 'x'` for every source to force
* esbuild to keep crawling due to potential side effects.
*/
function extractImportPaths(code: string) {
// empty singleline & multiline comments to avoid matching comments
code = code
.replace(multilineCommentsRE, '/* */')
.replace(singlelineCommentsRE, '')

let js = ''
let m
while ((m = importsRE.exec(code)) != null) {
// This is necessary to avoid infinite loops with zero-width matches
if (m.index === importsRE.lastIndex) {
importsRE.lastIndex++
}
js += `\nimport ${m[1]}`
}
return js
}

export function shouldExternalizeDep(
resolvedId: string,
rawId: string
Expand Down
47 changes: 44 additions & 3 deletions scripts/jestPerTestSetup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import {
ViteDevServer,
UserConfig,
PluginOption,
ResolvedConfig
ResolvedConfig,
Logger
} from 'vite'
import { Page } from 'playwright-chromium'
// eslint-disable-next-line node/no-extraneous-import
import { RollupWatcher, RollupWatcherEvent } from 'rollup'
import { RollupError, RollupWatcher, RollupWatcherEvent } from 'rollup'

const isBuildTest = !!process.env.VITE_TEST_BUILD

Expand All @@ -25,6 +26,7 @@ declare global {
const page: Page | undefined

const browserLogs: string[]
const serverLogs: string[]
const viteTestUrl: string | undefined
const watcher: RollupWatcher | undefined
let beforeAllError: Error | null // error caught in beforeAll, useful if you want to test error scenarios on build
Expand All @@ -34,6 +36,7 @@ declare const global: {
page?: Page

browserLogs: string[]
serverLogs: string[]
viteTestUrl?: string
watcher?: RollupWatcher
beforeAllError: Error | null
Expand Down Expand Up @@ -87,6 +90,8 @@ beforeAll(async () => {
}
}

const serverLogs: string[] = []

const options: UserConfig = {
root: rootDir,
logLevel: 'silent',
Expand All @@ -105,9 +110,12 @@ beforeAll(async () => {
build: {
// skip transpilation during tests to make it faster
target: 'esnext'
}
},
customLogger: createInMemoryLogger(serverLogs)
}

global.serverLogs = serverLogs

if (!isBuildTest) {
process.env.VITE_INLINE = 'inline-serve'
server = await (await createServer(options)).listen()
Expand Down Expand Up @@ -153,6 +161,7 @@ beforeAll(async () => {

afterAll(async () => {
global.page?.off('console', onConsole)
global.serverLogs = []
await global.page?.close()
await server?.close()
const beforeAllErr = getBeforeAllError()
Expand Down Expand Up @@ -221,3 +230,35 @@ export async function notifyRebuildComplete(
})
return watcher.removeListener('event', callback)
}

function createInMemoryLogger(logs: string[]): Logger {
const loggedErrors = new WeakSet<Error | RollupError>()
const warnedMessages = new Set<string>()

const logger: Logger = {
hasWarned: false,
hasErrorLogged: (err) => loggedErrors.has(err),
clearScreen: () => {},
info(msg) {
logs.push(msg)
},
warn(msg) {
logs.push(msg)
logger.hasWarned = true
},
warnOnce(msg) {
if (warnedMessages.has(msg)) return
logs.push(msg)
logger.hasWarned = true
warnedMessages.add(msg)
},
error(msg, opts) {
logs.push(msg)
if (opts?.error) {
loggedErrors.add(opts.error)
}
}
}

return logger
}

0 comments on commit 7ed8702

Please sign in to comment.