1 | import { isPlainObject } from 'shared/util'
|
2 |
|
3 | const vm = require('vm')
|
4 | const path = require('path')
|
5 | const resolve = require('resolve')
|
6 | const NativeModule = require('module')
|
7 |
|
8 | function createSandbox (context) {
|
9 | const sandbox = {
|
10 | Buffer,
|
11 | console,
|
12 | process,
|
13 | setTimeout,
|
14 | setInterval,
|
15 | setImmediate,
|
16 | clearTimeout,
|
17 | clearInterval,
|
18 | clearImmediate,
|
19 | __VUE_SSR_CONTEXT__: context
|
20 | }
|
21 | sandbox.global = sandbox
|
22 | return sandbox
|
23 | }
|
24 |
|
25 | function compileModule (files, basedir, runInNewContext) {
|
26 | const compiledScripts = {}
|
27 | const resolvedModules = {}
|
28 |
|
29 | function getCompiledScript (filename) {
|
30 | if (compiledScripts[filename]) {
|
31 | return compiledScripts[filename]
|
32 | }
|
33 | const code = files[filename]
|
34 | const wrapper = NativeModule.wrap(code)
|
35 | const script = new vm.Script(wrapper, {
|
36 | filename,
|
37 | displayErrors: true
|
38 | })
|
39 | compiledScripts[filename] = script
|
40 | return script
|
41 | }
|
42 |
|
43 | function evaluateModule (filename, sandbox, evaluatedFiles = {}) {
|
44 | if (evaluatedFiles[filename]) {
|
45 | return evaluatedFiles[filename]
|
46 | }
|
47 |
|
48 | const script = getCompiledScript(filename)
|
49 | const compiledWrapper = runInNewContext === false
|
50 | ? script.runInThisContext()
|
51 | : script.runInNewContext(sandbox)
|
52 | const m = { exports: {}}
|
53 | const r = file => {
|
54 | file = path.posix.join('.', file)
|
55 | if (files[file]) {
|
56 | return evaluateModule(file, sandbox, evaluatedFiles)
|
57 | } else if (basedir) {
|
58 | return require(
|
59 | resolvedModules[file] ||
|
60 | (resolvedModules[file] = resolve.sync(file, { basedir }))
|
61 | )
|
62 | } else {
|
63 | return require(file)
|
64 | }
|
65 | }
|
66 | compiledWrapper.call(m.exports, m.exports, r, m)
|
67 |
|
68 | const res = Object.prototype.hasOwnProperty.call(m.exports, 'default')
|
69 | ? m.exports.default
|
70 | : m.exports
|
71 | evaluatedFiles[filename] = res
|
72 | return res
|
73 | }
|
74 | return evaluateModule
|
75 | }
|
76 |
|
77 | function deepClone (val) {
|
78 | if (isPlainObject(val)) {
|
79 | const res = {}
|
80 | for (const key in val) {
|
81 | res[key] = deepClone(val[key])
|
82 | }
|
83 | return res
|
84 | } else if (Array.isArray(val)) {
|
85 | return val.slice()
|
86 | } else {
|
87 | return val
|
88 | }
|
89 | }
|
90 |
|
91 | export function createBundleRunner (entry, files, basedir, runInNewContext) {
|
92 | const evaluate = compileModule(files, basedir, runInNewContext)
|
93 | if (runInNewContext !== false && runInNewContext !== 'once') {
|
94 |
|
95 |
|
96 |
|
97 | return (userContext = {}) => new Promise(resolve => {
|
98 | userContext._registeredComponents = new Set()
|
99 | const res = evaluate(entry, createSandbox(userContext))
|
100 | resolve(typeof res === 'function' ? res(userContext) : res)
|
101 | })
|
102 | } else {
|
103 |
|
104 |
|
105 |
|
106 |
|
107 | let runner
|
108 | let initialContext
|
109 | return (userContext = {}) => new Promise(resolve => {
|
110 | if (!runner) {
|
111 | const sandbox = runInNewContext === 'once'
|
112 | ? createSandbox()
|
113 | : global
|
114 |
|
115 |
|
116 | initialContext = sandbox.__VUE_SSR_CONTEXT__ = {}
|
117 | runner = evaluate(entry, sandbox)
|
118 |
|
119 |
|
120 | delete sandbox.__VUE_SSR_CONTEXT__
|
121 | if (typeof runner !== 'function') {
|
122 | throw new Error(
|
123 | 'bundle export should be a function when using ' +
|
124 | '{ runInNewContext: false }.'
|
125 | )
|
126 | }
|
127 | }
|
128 | userContext._registeredComponents = new Set()
|
129 |
|
130 |
|
131 | if (initialContext._styles) {
|
132 | userContext._styles = deepClone(initialContext._styles)
|
133 |
|
134 |
|
135 |
|
136 | const renderStyles = initialContext._renderStyles
|
137 | if (renderStyles) {
|
138 | Object.defineProperty(userContext, 'styles', {
|
139 | enumerable: true,
|
140 | get () {
|
141 | return renderStyles(userContext._styles)
|
142 | }
|
143 | })
|
144 | }
|
145 | }
|
146 |
|
147 | resolve(runner(userContext))
|
148 | })
|
149 | }
|
150 | }
|