Skip to content

Commit e2ce59a

Browse files
committed
perf: optimize out jest.exodus and expect from bundles if not used
1 parent e784aa6 commit e2ce59a

File tree

3 files changed

+54
-16
lines changed

3 files changed

+54
-16
lines changed

bundler/bundle.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ export const build = async (...files) => {
224224
await importSource('./modules/globals.cjs')
225225
}
226226

227+
const haveJestAPIs = { expect: false, exodus: false }
227228
if (options.jest) {
228229
const { jestConfig } = options
229230
const preload = [...(jestConfig.setupFiles || []), ...(jestConfig.setupFilesAfterEnv || [])]
@@ -244,6 +245,14 @@ export const build = async (...files) => {
244245

245246
// copy of loader/jest
246247
input.push(`await (await import(${stringify(resolveSrc('jest.setup.js'))})).setupJest();`)
248+
249+
const ignoreFrom = /\/test\/src\/(jest(\.(mock|snapshot))?\.js|engine\.pure\.cjs|expect\.cjs)$/u // rechecked to not use those apis if no outside usage
250+
specificLoadPipeline.push(async (source, filepath) => {
251+
if (ignoreFrom.test(filepath.replaceAll('\\', '/'))) return source
252+
haveJestAPIs.expect ||= /(^|[^#])\bexpect([(.]|$)/mu.test(source)
253+
haveJestAPIs.exodus ||= /jest\.exodus/u.test(source)
254+
return source
255+
})
247256
}
248257

249258
for (const file of files) importFile(file)
@@ -421,6 +430,8 @@ export const build = async (...files) => {
421430
EXODUS_TEST_FSFILES: stringify(emptyToUndefined(fsfiles)), // TODO: can we safely use relative paths?
422431
EXODUS_TEST_FSFILES_CONTENTS: stringify(emptyToUndefined([...fsFilesContents.entries()])),
423432
EXODUS_TEST_FSDIRS: stringify(emptyToUndefined([...fsFilesDirs.entries()])),
433+
EXODUS_TEST_LOAD_EXPECT: stringify(haveJestAPIs.expect),
434+
EXODUS_TEST_LOAD_JESTEXODUS: stringify(haveJestAPIs.exodus),
424435
},
425436
alias: {
426437
// Jest, tape and node:test
@@ -552,10 +563,22 @@ export const build = async (...files) => {
552563
let res = await buildWrap(config)
553564
assert.equal(res instanceof Error, res.errors.length > 0)
554565

566+
let needRerun = false
555567
if (fsFilesContents.size > 0 || fsFilesDirs.size > 0) {
556568
// re-run as we detected that tests depend on fsReadFileSync contents
557569
config.define.EXODUS_TEST_FSFILES_CONTENTS = stringify([...fsFilesContents.entries()])
558570
config.define.EXODUS_TEST_FSDIRS = stringify([...fsFilesDirs.entries()])
571+
needRerun = true
572+
}
573+
574+
if (haveJestAPIs.expect || haveJestAPIs.exodus) {
575+
// re-run as we detected expect or jest.exodus usage and need to bundle those
576+
config.define.EXODUS_TEST_LOAD_EXPECT = stringify(haveJestAPIs.expect)
577+
config.define.EXODUS_TEST_LOAD_JESTEXODUS = stringify(haveJestAPIs.exodus)
578+
needRerun = true
579+
}
580+
581+
if (needRerun) {
559582
res = await buildWrap(config)
560583
assert.equal(res instanceof Error, res.errors.length > 0)
561584
}

src/expect.cjs

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,27 @@ function fixupAssertions() {
1313

1414
function loadExpect(loadReason) {
1515
if (expect) return expect
16-
try {
17-
expect = require('expect').expect
18-
} catch {
19-
throw new Error(`Failed to load 'expect', required for ${loadReason}`)
20-
}
16+
// eslint-disable-next-line no-undef
17+
if (typeof EXODUS_TEST_LOAD_EXPECT !== 'undefined' && EXODUS_TEST_LOAD_EXPECT === false) {
18+
if (loadReason === 'jest.mock') return // allow that and ignore if there is no usage
19+
throw new Error('FATAL: expect() was optimized out')
20+
} else {
21+
try {
22+
expect = require('expect').expect
23+
} catch {
24+
throw new Error(`Failed to load 'expect', required for ${loadReason}`)
25+
}
2126

22-
// console.log('expect load reason:', loadReason)
23-
try {
24-
expect.extend(require('jest-extended'))
25-
} catch {}
27+
// console.log('expect load reason:', loadReason)
28+
try {
29+
expect.extend(require('jest-extended'))
30+
} catch {}
2631

27-
for (const x of extend) expect.extend(...x)
28-
for (const [key, value] of set) expect[key] = value
29-
fixupAssertions()
30-
return expect
32+
for (const x of extend) expect.extend(...x)
33+
for (const [key, value] of set) expect[key] = value
34+
fixupAssertions()
35+
return expect
36+
}
3137
}
3238

3339
const areNumeric = (...args) => args.every((a) => typeof a === 'number' || typeof a === 'bigint')

src/jest.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,9 @@ if (process.env.EXODUS_TEST_PLATFORM !== 'deno' && globalThis.process) {
248248
}
249249
}
250250

251-
export const jest = {
252-
exodus: {
251+
// jest.exodus extension
252+
function makeJestExodus() {
253+
return {
253254
__proto__: null,
254255
...exodus,
255256
mock: {
@@ -265,7 +266,15 @@ export const jest = {
265266
return globalThis.WebSocket
266267
},
267268
},
268-
},
269+
}
270+
}
271+
272+
export const jest = {
273+
exodus:
274+
// eslint-disable-next-line no-undef
275+
typeof EXODUS_TEST_LOAD_JESTEXODUS === 'undefined' || EXODUS_TEST_LOAD_JESTEXODUS !== false
276+
? makeJestExodus()
277+
: undefined,
269278
setTimeout: (x) => {
270279
assert.equal(typeof x, 'number')
271280
defaultTimeout = x

0 commit comments

Comments
 (0)