Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: use module factory #11

Open
wants to merge 5 commits into
base: refactor-build-type-module
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 19 additions & 35 deletions packages/vite/misc/rolldown-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,33 +82,15 @@ var __toBinary = /* @__PURE__ */ (() => {
}
})()

// TODO: for now need to expose these utilities used by IsolatingModuleFinalizermodule
self.__toCommonJS = __toCommonJS
self.__toESM = __toESM
self.__export = __export
self.__reExport = __reExport

var rolldown_runtime = (self.rolldown_runtime = {
patching: false,
patchedModuleFactoryMap: {},
self.__rolldown_runtime = {
executeModuleStack: [],
moduleCache: {},
moduleFactoryMap: {},
define: function (id, factory) {
if (self.patching) {
this.patchedModuleFactoryMap[id] = factory
} else {
this.moduleFactoryMap[id] = factory
}
},
require: function (id) {
const parent =
this.executeModuleStack.length >= 1
? this.executeModuleStack[this.executeModuleStack.length - 1]
: null
const parent = this.executeModuleStack.at(-1)
if (this.moduleCache[id]) {
var module = this.moduleCache[id]
if (parent && module.parents.indexOf(parent) === -1) {
if (parent && !module.parents.includes(parent)) {
module.parents.push(parent)
}
return module.exports
Expand Down Expand Up @@ -139,25 +121,31 @@ var rolldown_runtime = (self.rolldown_runtime = {
},
})
this.executeModuleStack.push(id)
factory(this.require.bind(this), module, module.exports)
factory({
require: this.require.bind(this),
module,
exports: module.exports,
__toCommonJS,
__toESM,
__export,
__reExport,
})
this.executeModuleStack.pop()
return module.exports
},
patch: function (updateModuleIds, callback) {
self.patching = true

callback()

patch: function (newModuleFactoryMap) {
var boundaries = []
var invalidModuleIds = []
var acceptCallbacks = []

const updateModuleIds = Object.keys(newModuleFactoryMap)
for (var i = 0; i < updateModuleIds.length; i++) {
foundBoundariesAndInvalidModuleIds(
updateModuleIds[i],
boundaries,
invalidModuleIds,
acceptCallbacks,
this.moduleCache,
)
}

Expand All @@ -166,10 +154,7 @@ var rolldown_runtime = (self.rolldown_runtime = {
delete this.moduleCache[id]
}

for (var id in this.patchedModuleFactoryMap) {
this.moduleFactoryMap[id] = this.patchedModuleFactoryMap[id]
}
this.patchedModuleFactoryMap = {}
Object.assign(this.moduleFactoryMap, newModuleFactoryMap)

for (var i = 0; i < boundaries.length; i++) {
this.require(boundaries[i])
Expand All @@ -183,13 +168,12 @@ var rolldown_runtime = (self.rolldown_runtime = {
)
}

self.patching = false

function foundBoundariesAndInvalidModuleIds(
updateModuleId,
boundaries,
invalidModuleIds,
acceptCallbacks,
moduleCache,
) {
var queue = [{ moduleId: updateModuleId, chain: [updateModuleId] }]
var visited = {}
Expand All @@ -203,7 +187,7 @@ var rolldown_runtime = (self.rolldown_runtime = {
continue
}

var module = rolldown_runtime.moduleCache[moduleId]
var module = moduleCache[moduleId]
if (!module) {
continue
}
Expand Down Expand Up @@ -244,4 +228,4 @@ var rolldown_runtime = (self.rolldown_runtime = {
}
}
},
})
}
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"esbuild": "^0.24.0",
"postcss": "^8.4.49",
"react-refresh": "^0.14.2",
"rolldown": "./rolldown-0.15.0-b.tgz",
"rolldown": "link:../../../rolldown/packages/rolldown",
"rollup": "^4.23.0"
},
"optionalDependencies": {
Expand Down
Binary file not shown.
1 change: 1 addition & 0 deletions packages/vite/src/node/plugins/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ export function oxcResolvePlugin(
const filteredNoExternal = noExternal as true | string[]

return viteResolvePlugin({
dedupe: [],
resolveOptions: {
isBuild: options.isBuild,
isProduction: options.isProduction,
Expand Down
145 changes: 59 additions & 86 deletions packages/vite/src/node/server/environments/rolldown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ import type {
import { CLIENT_ENTRY, VITE_PACKAGE_DIR } from '../../constants'
import { injectEnvironmentToHooks } from '../../build'
import { cleanUrl } from '../../../shared/utils'
import { combineSourcemaps } from '../../utils'
import { genSourceMapUrl } from '../sourcemap'

const require = createRequire(import.meta.url)

Expand Down Expand Up @@ -290,7 +288,9 @@ class RolldownEnvironment extends DevEnvironment {
console.timeEnd(`[rolldown:${this.name}:build]`)
}

async buildHmr(file: string) {
async buildHmr(
file: string,
): Promise<rolldown.RolldownOutputChunk | undefined> {
logger.info(`hmr '${file}'`, { timestamp: true })
console.time(`[rolldown:${this.name}:rebuild]`)
const result = await this.instance.build()
Expand All @@ -301,27 +301,10 @@ class RolldownEnvironment extends DevEnvironment {
const chunk = result.output.find(
(v) => v.type === 'chunk' && v.name === 'hmr-update',
)
const updatePath = path.join(this.outDir, 'hmr-update.js')
if (!chunk) {
return [updatePath, '']
if (chunk) {
assert(chunk.type === 'chunk')
return chunk
}
assert(chunk.type === 'chunk')
const { output, stableIds } = patchIsolatedModuleChunk(chunk.code)
output.prepend(
`self.rolldown_runtime.patch(${JSON.stringify(stableIds)}, function(){\n`,
)
output.append('\n});')
let outputString = output.toString()
if (chunk.map) {
// collapse sourcemap
const map = combineSourcemaps(chunk.fileName, [
output.generateMap({ hires: 'boundary' }) as any,
chunk.map as any,
])
outputString = outputString.replace(/^\/\/# sourceMappingURL=.*/gm, '')
outputString += `\n//# sourceMappingURL=${genSourceMapUrl(map as any)}`
}
return [updatePath, outputString]
}

async handleUpdate(ctx: HmrContext): Promise<void> {
Expand All @@ -341,13 +324,16 @@ class RolldownEnvironment extends DevEnvironment {
this.rolldownDevOptions.hmr ||
this.rolldownDevOptions.ssrModuleRunner
) {
const result = await this.buildHmr(ctx.file)
const chunk = await this.buildHmr(ctx.file)
if (!chunk) {
return
}
if (this.name === 'client') {
ctx.server.ws.send('rolldown:hmr', result)
ctx.server.ws.send('rolldown:hmr', chunk.fileName)
} else {
this.getRunner().evaluate(
result[1].toString(),
path.join(this.outDir, result[0]),
chunk.code,
path.join(this.outDir, chunk.fileName),
)
}
} else {
Expand Down Expand Up @@ -384,64 +370,39 @@ class RolldownEnvironment extends DevEnvironment {
}
}

function patchIsolatedModuleChunk(code: string) {
// silly but we can do `render_app` on our own for now.
// extract isolated module between #region and #endregion then wrap by rolldown_runtime.define.
// https://github.com/rolldown/rolldown/blob/a29240168290e45b36fdc1a6d5c375281fb8dc3e/crates/rolldown/src/ecmascript/format/app.rs#L28-L55
const output = new MagicString(code)
const matches = code.matchAll(/^\/\/#region (.*)$/gm)
const stableIds: string[] = []
for (const match of matches) {
const stableId = match[1]!
stableIds.push(stableId)
const start = match.index!
const end = code.indexOf('//#endregion', match.index)
output.appendLeft(
start,
`rolldown_runtime.define(${JSON.stringify(stableId)},function(require, module, exports){\n\n`,
)
output.appendRight(end, `\n\n});\n`)
}
return { output, stableIds }
}

class RolldownModuleRunner {
// intercept globals
private context = {
rolldown_runtime: {} as any,
__rolldown_hot: {
send: () => {},
// TODO: avoid "self" on module runner
self: {
__rolldown_runtime: {} as any,
},
__require_external: require,
}

// TODO: support resolution?
async import(id: string): Promise<unknown> {
const mod = this.context.rolldown_runtime.moduleCache[id]
const mod = this.context.self.__rolldown_runtime.moduleCache[id]
assert(mod, `Module not found '${id}'`)
return mod.exports
}

evaluate(code: string, sourceURL: string) {
const context = {
self: this.context,
...this.context,
}
// extract sourcemap and move to the bottom
const sourcemap = code.match(/^\/\/# sourceMappingURL=.*/m)?.[0] ?? ''
if (sourcemap) {
code = code.replace(sourcemap, '')
}
code = `\
'use strict';(${Object.keys(context).join(',')})=>{{${code}
'use strict';(${Object.keys(this.context).join(',')})=>{{${code}
}}
//# sourceURL=${sourceURL}
//# sourceMappingSource=rolldown-module-runner
${sourcemap}
`
const fn = (0, eval)(code)
try {
fn(...Object.values(context))
fn(...Object.values(this.context))
} catch (e) {
console.error('[RolldownModuleRunner:ERROR]', e)
throw e
Expand All @@ -453,35 +414,47 @@ function patchRuntimePlugin(environment: RolldownEnvironment): rolldown.Plugin {
return {
name: 'vite:rolldown-patch-runtime',
renderChunk(code, chunk) {
if (!chunk.isEntry) {
return
}
// TODO: this magic string is heavy
const { output } = patchIsolatedModuleChunk(code)
assert(chunk.facadeModuleId)
const stableId = path.relative(
environment.config.root,
chunk.facadeModuleId,
)
output.append(
`\nrolldown_runtime.require(${JSON.stringify(stableId)});\n`,
)

// inject runtime
const runtimeCode = fs.readFileSync(
path.join(VITE_PACKAGE_DIR, 'misc', 'rolldown-runtime.js'),
'utf-8',
)
output.prepend(runtimeCode)
if (environment.name === 'client') {
output.prepend(getRolldownClientCode())
}
if (environment.rolldownDevOptions.reactRefresh) {
output.prepend(getReactRefreshRuntimeCode())

if (chunk.name === 'hmr-update') {
const output = new MagicString(code)
output.append(`
self.__rolldown_runtime.patch(__rolldown_modules);
`)
return {
code: output.toString(),
map: output.generateMap({ hires: 'boundary' }),
}
}
return {
code: output.toString(),
map: output.generateMap({ hires: 'boundary' }),

if (chunk.isEntry) {
const output = new MagicString(code)
assert(chunk.facadeModuleId)
const stableId = path.relative(
environment.config.root,
chunk.facadeModuleId,
)
output.append(`
Object.assign(self.__rolldown_runtime.moduleFactoryMap, __rolldown_modules);
self.__rolldown_runtime.require(${JSON.stringify(stableId)});
`)

// inject runtime
const runtimeCode = fs.readFileSync(
path.join(VITE_PACKAGE_DIR, 'misc', 'rolldown-runtime.js'),
'utf-8',
)
output.prepend(runtimeCode)
if (environment.name === 'client') {
output.prepend(getRolldownClientCode())
}
if (environment.rolldownDevOptions.reactRefresh) {
output.prepend(getReactRefreshRuntimeCode())
}
return {
code: output.toString(),
map: output.generateMap({ hires: 'boundary' }),
}
}
},
}
Expand Down Expand Up @@ -542,7 +515,7 @@ function getRolldownClientCode() {
code += `
const hot = createHotContext("/__rolldown");
hot.on("rolldown:hmr", (data) => {
(0, eval)(data[1]);
import("/" + data + "?t=" + Date.now());
});
self.__rolldown_hot = hot;
self.__rolldown_updateStyle = updateStyle;
Expand Down
6 changes: 6 additions & 0 deletions playground/rolldown-dev-ssr/__tests__/basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ test('basic', async () => {
expect(await res.text()).toContain('hydrated: <!-- -->false')
})

test.runIf(!isBuild)('server stacktrace', async () => {
const res = await page.goto(viteTestUrl + '/crash-ssr')
expect(await res?.text()).toContain('src/error.ts:8:9')
expect(res?.status()).toBe(500)
})

test.runIf(!isBuild)('hmr', async () => {
await page.goto(viteTestUrl)
await page.getByRole('button', { name: 'Count: 0' }).click()
Expand Down
Loading
Loading