-
Notifications
You must be signed in to change notification settings - Fork 69
/
preludeTemplate.js
106 lines (92 loc) · 3.92 KB
/
preludeTemplate.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// LavaMoat Prelude
(function() {
// identify the globalRef
const globalRef = (typeof self !== 'undefined') ? self : global
// config and bundle module store
const lavamoatConfig = { resources: {} }
const modules = {}
// initialize the kernel
const createKernel = __createKernel__
const { internalRequire } = createKernel({
lavamoatConfig,
loadModuleData,
getRelativeModuleId,
prepareModuleInitializerArgs,
})
// create a lavamoat pulic API for loading modules over multiple files
const lavamoatPublicApi = Object.freeze({
loadBundle: Object.freeze(loadBundle),
})
globalRef.LavaMoat = lavamoatPublicApi
return loadBundle
// it is called by the modules collection that will be appended to this file
function loadBundle (newModules, entryPoints, newConfig) {
// verify + load config
Object.entries(newConfig.resources || {}).forEach(([packageName, packageConfig]) => {
if (packageName in lavamoatConfig) {
throw new Error(`LavaMoat - loadBundle encountered redundant config definition for package "${packageName}"`)
}
lavamoatConfig.resources[packageName] = packageConfig
})
// verify + load in each module
for (const [moduleId, moduleData] of Object.entries(newModules)) {
// verify that module is new
if (moduleId in modules) {
throw new Error(`LavaMoat - loadBundle encountered redundant module definition for id "${moduleId}"`)
}
// convert all module source to string
// this could happen at build time,
// but shipping it as code makes it easier to debug, maybe
for (let moduleData of Object.values(newModules)) {
let moduleSource = `(${moduleData.source})`
if (moduleData.file) {
const moduleSourceLabel = `// moduleSource: ${moduleData.file}`
moduleSource += `\n\n${moduleSourceLabel}`
}
moduleData.sourceString = moduleSource
}
// add the module
modules[moduleId] = moduleData
}
// run each of entryPoints
const entryExports = Array.prototype.map.call(entryPoints, (entryId) => {
return internalRequire(entryId)
})
// webpack compat: return the first module's exports
return entryExports[0]
}
function loadModuleData (moduleId) {
return modules[moduleId]
}
function getRelativeModuleId (parentModuleId, requestedName) {
const parentModuleData = modules[parentModuleId]
if (!(requestedName in parentModuleData.deps)) {
console.warn(`missing dep: ${parentModuleData.packageName} requested ${requestedName}`)
}
return parentModuleData.deps[requestedName] || requestedName
}
function prepareModuleInitializerArgs (requireRelativeWithContext, moduleObj, moduleData) {
const require = requireRelativeWithContext
const module = moduleObj
const exports = moduleObj.exports
// browserify goop:
// this "modules" interface is exposed to the browserify moduleInitializer
// https://github.com/browserify/browser-pack/blob/cd0bd31f8c110e19a80429019b64e887b1a82b2b/prelude.js#L38
// browserify's browser-resolve uses "arguments[4]" to do direct module initializations
// browserify seems to do this when module references are redirected by the "browser" field
// this proxy shims this behavior
// this is utilized by browserify's dedupe feature
// though in the original browser-pack prelude it has a side effect that it is re-instantiated from the original module (no shared closure state)
const directModuleInstantiationInterface = new Proxy({}, {
get (_, targetModuleId) {
const fakeModuleDefinition = [fakeModuleInitializer]
return fakeModuleDefinition
function fakeModuleInitializer () {
const targetModuleExports = requireRelativeWithContext(targetModuleId)
moduleObj.exports = targetModuleExports
}
}
})
return [require, module, exports, null, directModuleInstantiationInterface]
}
})()