Skip to content

Commit

Permalink
⚡ feat: Make config loading in bundlers async (#469)
Browse files Browse the repository at this point in the history
## Description

Improve startup time peformance by loading configs async

## Testing

Explain the quality checks that have been done on the code changes

## Additional Information

- [ ] I read the [contributing docs](../docs/contributing.md) (if this
is your first contribution)

Your ENS/address:

---------

Co-authored-by: Will Cory <[email protected]>
  • Loading branch information
roninjin10 and Will Cory authored Sep 18, 2023
1 parent e99fcd0 commit dbc2da6
Show file tree
Hide file tree
Showing 15 changed files with 516 additions and 85 deletions.
12 changes: 12 additions & 0 deletions .changeset/calm-ads-burn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@evmts/bundler": patch
"@evmts/bun-plugin": patch
"@evmts/config": patch
"@evmts/esbuild-plugin": patch
"@evmts/rollup-plugin": patch
"@evmts/rspack-plugin": patch
"@evmts/vite-plugin": patch
"@evmts/webpack-plugin": patch
---

Made @evmts/config loading async
20 changes: 10 additions & 10 deletions bundlers/bun/src/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { evmtsBunPlugin } from '.'
import { file } from './bunFile'
import { bundler } from '@evmts/bundler'
import { loadConfig } from '@evmts/config'
import { loadConfigAsync } from '@evmts/config'
import { exists, readFile } from 'fs/promises'
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest'

vi.mock('@evmts/config', async () => ({
...((await vi.importActual('@evmts/config')) as {}),
loadConfig: vi.fn(),
loadConfigAsync: vi.fn(),
}))

vi.mock('@evmts/bundler', () => ({
Expand All @@ -29,7 +29,7 @@ const mockFile = file as Mock
const mockExists = exists as Mock

const mockBundler = bundler as Mock
const mockLoadConfig = loadConfig as Mock
const mockLoadConfig = loadConfigAsync as Mock
mockBundler.mockReturnValue({
resolveEsmModule: vi.fn(),
})
Expand Down Expand Up @@ -80,7 +80,7 @@ describe('evmtsBunPlugin', () => {
onResolve: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [onLoadFilter, onLoadFn] = mockBuild.onLoad.mock.lastCall ?? []

Expand Down Expand Up @@ -121,7 +121,7 @@ describe('evmtsBunPlugin', () => {
onResolve: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [onLoadFilter, onLoadFn] = mockBuild.onLoad.mock.lastCall ?? []

Expand Down Expand Up @@ -150,7 +150,7 @@ describe('evmtsBunPlugin', () => {
onLoad: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [_, onResolveFn] = mockBuild.onResolve.mock.calls[0]
const resolved = onResolveFn({
Expand All @@ -168,7 +168,7 @@ describe('evmtsBunPlugin', () => {
onLoad: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [_, onResolveFn] = mockBuild.onResolve.mock.calls[0]

Expand All @@ -192,7 +192,7 @@ describe('evmtsBunPlugin', () => {
onResolve: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [_, onLoadFn] = mockBuild.onLoad.mock.lastCall ?? []

Expand All @@ -214,7 +214,7 @@ describe('evmtsBunPlugin', () => {
onResolve: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [_, onLoadFn] = mockBuild.onLoad.mock.lastCall ?? []

Expand All @@ -237,7 +237,7 @@ describe('evmtsBunPlugin', () => {
onResolve: vi.fn(),
config: {} as any,
}
plugin.setup(mockBuild)
await plugin.setup(mockBuild)

const [_, onLoadFn] = mockBuild.onLoad.mock.lastCall ?? []

Expand Down
12 changes: 8 additions & 4 deletions bundlers/bun/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { bunFileAccesObject } from './bunFileAccessObject'
import { bundler } from '@evmts/bundler'
import { loadConfig } from '@evmts/config'
import { loadConfigAsync } from '@evmts/config'
import type { BunPlugin } from 'bun'

type EvmtsBunPluginOptions = {}

type EvmtsBunPlugin = (options?: EvmtsBunPluginOptions) => BunPlugin

export const evmtsBunPlugin: EvmtsBunPlugin = () => {
const config = loadConfig(process.cwd())
const moduleResolver = bundler(config, console, bunFileAccesObject)
return {
name: '@evmts/esbuild-plugin',
setup(build) {
async setup(build) {
const config = await loadConfigAsync(
process.cwd(),
console,
bunFileAccesObject.exists,
)
const moduleResolver = bundler(config, console, bunFileAccesObject)
/**
* @evmts/core is used to construct the evmts modules for solidity files
* sometimes the solidity file might exist in the node_modules folder
Expand Down
10 changes: 5 additions & 5 deletions bundlers/bundler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@
"src"
],
"scripts": {
"test": "vitest --coverage",
"test:coverage": "vitest run --coverage",
"test:run": "vitest run",
"test:ui": "vitest --ui",
"build": "nx run-many --targets=build:dist,build:types --projects=@evmts/bundler ",
"build:dist": "tsup",
"build:types": "tsc --emitDeclarationOnly",
Expand All @@ -43,7 +39,11 @@
"format:check": "rome format .",
"lint": "rome check . --apply-unsafe",
"lint:check": "rome check . --verbose",
"package:up": "pnpm up --latest"
"package:up": "pnpm up --latest",
"test": "vitest --coverage",
"test:coverage": "vitest run --coverage",
"test:run": "vitest run",
"test:ui": "vitest --ui"
},
"dependencies": {
"@evmts/config": "workspace:^",
Expand Down
8 changes: 4 additions & 4 deletions bundlers/bundler/src/unplugin.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as packageJson from '../package.json'
import { bundler } from './bundler'
import { unpluginFn } from './unplugin'
import { loadConfig } from '@evmts/config'
import { loadConfigAsync } from '@evmts/config'
import { existsSync } from 'fs'
import { createRequire } from 'module'
import type { UnpluginBuildContext, UnpluginContext } from 'unplugin'
Expand All @@ -22,7 +22,7 @@ vi.mock('module', async () => ({

vi.mock('@evmts/config', async () => ({
...((await vi.importActual('@evmts/config')) as {}),
loadConfig: vi.fn(),
loadConfigAsync: vi.fn(),
}))
vi.mock('./bundler', () => ({
bundler: vi.fn(),
Expand All @@ -36,7 +36,7 @@ vi.mock('fs', async () => ({
const mockExistsSync = existsSync as Mock

const mockBundler = bundler as Mock
const mockLoadConfig = loadConfig as Mock
const mockLoadConfig = loadConfigAsync as Mock
mockBundler.mockReturnValue({
resolveEsmModule: vi.fn(),
})
Expand Down Expand Up @@ -79,7 +79,7 @@ describe('unpluginFn', () => {
// call buildstart with mockPlugin as this
await plugin.buildStart?.call(mockPlugin)

expect(loadConfig).toHaveBeenCalledWith(mockCwd)
expect(loadConfigAsync).toHaveBeenCalledWith(mockCwd)
expect((bundler as Mock).mock.lastCall).toMatchInlineSnapshot(`
[
{
Expand Down
4 changes: 2 additions & 2 deletions bundlers/bundler/src/unplugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as packageJson from '../package.json'
import { bundler } from './bundler'
import type { FileAccessObject } from './types'
import { type ResolvedConfig, loadConfig } from '@evmts/config'
import { type ResolvedConfig, loadConfigAsync } from '@evmts/config'
import { existsSync, readFileSync } from 'fs'
import { readFile } from 'fs/promises'
import { createRequire } from 'module'
Expand Down Expand Up @@ -55,7 +55,7 @@ export const unpluginFn: UnpluginFactory<
name: '@evmts/rollup-plugin',
version: packageJson.version,
async buildStart() {
config = loadConfig(process.cwd())
config = await loadConfigAsync(process.cwd())
moduleResolver = bundler(config, console, fao)
this.addWatchFile('./tsconfig.json')
},
Expand Down
114 changes: 58 additions & 56 deletions bundlers/bundler/src/utils/resolvePromise.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,51 +4,51 @@ import fs from 'fs'
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest'

const fao: FileAccessObject = {
existsSync: (filePath: string) => fs.existsSync(filePath),
readFile: (filePath: string, encoding: string) =>
Promise.resolve(
fs.readFileSync(filePath, { encoding: encoding as 'utf8' }),
),
readFileSync: (filePath: string) => fs.readFileSync(filePath, 'utf8'),
existsSync: (filePath: string) => fs.existsSync(filePath),
readFile: (filePath: string, encoding: string) =>
Promise.resolve(
fs.readFileSync(filePath, { encoding: encoding as 'utf8' }),
),
readFileSync: (filePath: string) => fs.readFileSync(filePath, 'utf8'),
}

let logger: Logger = {
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
log: vi.fn(),
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
log: vi.fn(),
}

describe('resolvePromise', () => {
beforeEach(() => {
logger = {
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
log: vi.fn(),
}
})
beforeEach(() => {
logger = {
error: vi.fn(),
info: vi.fn(),
warn: vi.fn(),
log: vi.fn(),
}
})

it('should resolve a file path in the base directory', async () => {
const resolvedPath = await resolvePromise(
'./resolvePromise.spec.ts',
__dirname,
fao,
logger,
)
expect(
resolvedPath.endsWith(
'evmts-monorepo/bundlers/bundler/src/utils/resolvePromise.spec.ts',
),
).toBe(true)
})
it('should resolve a file path in the base directory', async () => {
const resolvedPath = await resolvePromise(
'./resolvePromise.spec.ts',
__dirname,
fao,
logger,
)
expect(
resolvedPath.endsWith(
'evmts-monorepo/bundlers/bundler/src/utils/resolvePromise.spec.ts',
),
).toBe(true)
})

it('should handle readFile throwing', async () => {
fao.readFile = () => Promise.reject('readFile error')
await expect(
resolvePromise('./resolvePromise.spec.tst', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot('"readFile error"')
expect((logger.error as Mock).mock.calls).toMatchInlineSnapshot(`
it('should handle readFile throwing', async () => {
fao.readFile = () => Promise.reject('readFile error')
await expect(
resolvePromise('./resolvePromise.spec.tst', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot('"readFile error"')
expect((logger.error as Mock).mock.calls).toMatchInlineSnapshot(`
[
[
"readFile error",
Expand Down Expand Up @@ -88,16 +88,16 @@ describe('resolvePromise', () => {
],
]
`)
})
})

it('should throw an error for non-existent file', async () => {
fao.existsSync = () => false
await expect(
resolvePromise('./resolvePromise.spec.tst', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot(
"\"Cannot find module './resolvePromise.spec.tst' from './src/utils'\"",
)
expect((logger.error as Mock).mock.calls).toMatchInlineSnapshot(`
it('should throw an error for non-existent file', async () => {
fao.existsSync = () => false
await expect(
resolvePromise('./resolvePromise.spec.tst', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot(
"\"Cannot find module './resolvePromise.spec.tst' from './src/utils'\"",
)
expect((logger.error as Mock).mock.calls).toMatchInlineSnapshot(`
[
[
[Error: Cannot find module './resolvePromise.spec.tst' from './src/utils'],
Expand All @@ -107,19 +107,21 @@ describe('resolvePromise', () => {
],
]
`)
})
})

it('should throw an error if existsSync throws', () => {
fao.existsSync = () => {
throw new Error('existsSync error')
}
expect(
resolvePromise('./resolvePromise.spec.ts', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot('"existsSync error"')
expect((logger.error as Mock).mock.calls[0].slice(0, 2)).toMatchInlineSnapshot(`
it('should throw an error if existsSync throws', () => {
fao.existsSync = () => {
throw new Error('existsSync error')
}
expect(
resolvePromise('./resolvePromise.spec.ts', './src/utils', fao, logger),
).rejects.toThrowErrorMatchingInlineSnapshot('"existsSync error"')
expect(
(logger.error as Mock).mock.calls[0].slice(0, 2),
).toMatchInlineSnapshot(`
[
[Error: existsSync error],
]
`)
})
})
})
2 changes: 1 addition & 1 deletion config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"type": "module",
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "types/index.d.ts",
"types": "types/src/index.d.ts",
"files": [
"dist",
"types",
Expand Down
34 changes: 34 additions & 0 deletions config/src/fileExists.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { fileExists } from './fileExists'
import { constants } from 'fs'
import { access } from 'fs/promises'
import { type Mock, afterEach, describe, expect, it, vi } from 'vitest'

vi.mock('fs/promises')

describe('fileExists', () => {
afterEach(() => {
vi.clearAllMocks()
})

const accessMock = access as Mock
it('should return true if the file exists', async () => {
accessMock.mockResolvedValueOnce(undefined)
const result = await fileExists('path-to-existing-file.txt')
expect(result).toBe(true)
expect(access).toHaveBeenCalledWith(
'path-to-existing-file.txt',
constants.F_OK,
)
})

it('should return false if the file does not exist', async () => {
const mockError = new Error('File does not exist')
accessMock.mockRejectedValueOnce(mockError)
const result = await fileExists('path-to-non-existing-file.txt')
expect(result).toBe(false)
expect(access).toHaveBeenCalledWith(
'path-to-non-existing-file.txt',
constants.F_OK,
)
})
})
Loading

1 comment on commit dbc2da6

@vercel
Copy link

@vercel vercel bot commented on dbc2da6 Sep 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

evmts-docs – ./

evmts.dev
evmts-docs-evmts.vercel.app
evmts-docs-git-main-evmts.vercel.app

Please sign in to comment.