diff options
Diffstat (limited to 'node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js')
| -rw-r--r-- | node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js b/node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js new file mode 100644 index 00000000..16c33c41 --- /dev/null +++ b/node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js @@ -0,0 +1,150 @@ +import { isPlainObject } from 'shared/util' + +const vm = require('vm') +const path = require('path') +const resolve = require('resolve') +const NativeModule = require('module') + +function createSandbox (context) { + const sandbox = { + Buffer, + console, + process, + setTimeout, + setInterval, + setImmediate, + clearTimeout, + clearInterval, + clearImmediate, + __VUE_SSR_CONTEXT__: context + } + sandbox.global = sandbox + return sandbox +} + +function compileModule (files, basedir, runInNewContext) { + const compiledScripts = {} + const resolvedModules = {} + + function getCompiledScript (filename) { + if (compiledScripts[filename]) { + return compiledScripts[filename] + } + const code = files[filename] + const wrapper = NativeModule.wrap(code) + const script = new vm.Script(wrapper, { + filename, + displayErrors: true + }) + compiledScripts[filename] = script + return script + } + + function evaluateModule (filename, sandbox, evaluatedFiles = {}) { + if (evaluatedFiles[filename]) { + return evaluatedFiles[filename] + } + + const script = getCompiledScript(filename) + const compiledWrapper = runInNewContext === false + ? script.runInThisContext() + : script.runInNewContext(sandbox) + const m = { exports: {}} + const r = file => { + file = path.posix.join('.', file) + if (files[file]) { + return evaluateModule(file, sandbox, evaluatedFiles) + } else if (basedir) { + return require( + resolvedModules[file] || + (resolvedModules[file] = resolve.sync(file, { basedir })) + ) + } else { + return require(file) + } + } + compiledWrapper.call(m.exports, m.exports, r, m) + + const res = Object.prototype.hasOwnProperty.call(m.exports, 'default') + ? m.exports.default + : m.exports + evaluatedFiles[filename] = res + return res + } + return evaluateModule +} + +function deepClone (val) { + if (isPlainObject(val)) { + const res = {} + for (const key in val) { + res[key] = deepClone(val[key]) + } + return res + } else if (Array.isArray(val)) { + return val.slice() + } else { + return val + } +} + +export function createBundleRunner (entry, files, basedir, runInNewContext) { + const evaluate = compileModule(files, basedir, runInNewContext) + if (runInNewContext !== false && runInNewContext !== 'once') { + // new context mode: creates a fresh context and re-evaluate the bundle + // on each render. Ensures entire application state is fresh for each + // render, but incurs extra evaluation cost. + return (userContext = {}) => new Promise(resolve => { + userContext._registeredComponents = new Set() + const res = evaluate(entry, createSandbox(userContext)) + resolve(typeof res === 'function' ? res(userContext) : res) + }) + } else { + // direct mode: instead of re-evaluating the whole bundle on + // each render, it simply calls the exported function. This avoids the + // module evaluation costs but requires the source code to be structured + // slightly differently. + let runner // lazy creation so that errors can be caught by user + let initialContext + return (userContext = {}) => new Promise(resolve => { + if (!runner) { + const sandbox = runInNewContext === 'once' + ? createSandbox() + : global + // the initial context is only used for collecting possible non-component + // styles injected by vue-style-loader. + initialContext = sandbox.__VUE_SSR_CONTEXT__ = {} + runner = evaluate(entry, sandbox) + // On subsequent renders, __VUE_SSR_CONTEXT__ will not be available + // to prevent cross-request pollution. + delete sandbox.__VUE_SSR_CONTEXT__ + if (typeof runner !== 'function') { + throw new Error( + 'bundle export should be a function when using ' + + '{ runInNewContext: false }.' + ) + } + } + userContext._registeredComponents = new Set() + + // vue-style-loader styles imported outside of component lifecycle hooks + if (initialContext._styles) { + userContext._styles = deepClone(initialContext._styles) + // #6353 ensure "styles" is exposed even if no styles are injected + // in component lifecycles. + // the renderStyles fn is exposed by vue-style-loader >= 3.0.3 + const renderStyles = initialContext._renderStyles + if (renderStyles) { + Object.defineProperty(userContext, 'styles', { + enumerable: true, + get () { + return renderStyles(userContext._styles) + } + }) + } + } + + resolve(runner(userContext)) + }) + } +} |
