init
This commit is contained in:
151
node_modules/vue/src/server/bundle-renderer/create-bundle-renderer.js
generated
vendored
Normal file
151
node_modules/vue/src/server/bundle-renderer/create-bundle-renderer.js
generated
vendored
Normal file
@@ -0,0 +1,151 @@
|
||||
/* @flow */
|
||||
|
||||
import { createPromiseCallback } from '../util'
|
||||
import { createBundleRunner } from './create-bundle-runner'
|
||||
import type { Renderer, RenderOptions } from '../create-renderer'
|
||||
import { createSourceMapConsumers, rewriteErrorTrace } from './source-map-support'
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
const PassThrough = require('stream').PassThrough
|
||||
|
||||
const INVALID_MSG =
|
||||
'Invalid server-rendering bundle format. Should be a string ' +
|
||||
'or a bundle Object of type:\n\n' +
|
||||
`{
|
||||
entry: string;
|
||||
files: { [filename: string]: string; };
|
||||
maps: { [filename: string]: string; };
|
||||
}\n`
|
||||
|
||||
// The render bundle can either be a string (single bundled file)
|
||||
// or a bundle manifest object generated by vue-ssr-webpack-plugin.
|
||||
type RenderBundle = {
|
||||
basedir?: string;
|
||||
entry: string;
|
||||
files: { [filename: string]: string; };
|
||||
maps: { [filename: string]: string; };
|
||||
modules?: { [filename: string]: Array<string> };
|
||||
};
|
||||
|
||||
export function createBundleRendererCreator (
|
||||
createRenderer: (options?: RenderOptions) => Renderer
|
||||
) {
|
||||
return function createBundleRenderer (
|
||||
bundle: string | RenderBundle,
|
||||
rendererOptions?: RenderOptions = {}
|
||||
) {
|
||||
let files, entry, maps
|
||||
let basedir = rendererOptions.basedir
|
||||
|
||||
// load bundle if given filepath
|
||||
if (
|
||||
typeof bundle === 'string' &&
|
||||
/\.js(on)?$/.test(bundle) &&
|
||||
path.isAbsolute(bundle)
|
||||
) {
|
||||
if (fs.existsSync(bundle)) {
|
||||
const isJSON = /\.json$/.test(bundle)
|
||||
basedir = basedir || path.dirname(bundle)
|
||||
bundle = fs.readFileSync(bundle, 'utf-8')
|
||||
if (isJSON) {
|
||||
try {
|
||||
bundle = JSON.parse(bundle)
|
||||
} catch (e) {
|
||||
throw new Error(`Invalid JSON bundle file: ${bundle}`)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Cannot locate bundle file: ${bundle}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bundle === 'object') {
|
||||
entry = bundle.entry
|
||||
files = bundle.files
|
||||
basedir = basedir || bundle.basedir
|
||||
maps = createSourceMapConsumers(bundle.maps)
|
||||
if (typeof entry !== 'string' || typeof files !== 'object') {
|
||||
throw new Error(INVALID_MSG)
|
||||
}
|
||||
} else if (typeof bundle === 'string') {
|
||||
entry = '__vue_ssr_bundle__'
|
||||
files = { '__vue_ssr_bundle__': bundle }
|
||||
maps = {}
|
||||
} else {
|
||||
throw new Error(INVALID_MSG)
|
||||
}
|
||||
|
||||
const renderer = createRenderer(rendererOptions)
|
||||
|
||||
const run = createBundleRunner(
|
||||
entry,
|
||||
files,
|
||||
basedir,
|
||||
rendererOptions.runInNewContext
|
||||
)
|
||||
|
||||
return {
|
||||
renderToString: (context?: Object, cb: any) => {
|
||||
if (typeof context === 'function') {
|
||||
cb = context
|
||||
context = {}
|
||||
}
|
||||
|
||||
let promise
|
||||
if (!cb) {
|
||||
({ promise, cb } = createPromiseCallback())
|
||||
}
|
||||
|
||||
run(context).catch(err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
cb(err)
|
||||
}).then(app => {
|
||||
if (app) {
|
||||
renderer.renderToString(app, context, (err, res) => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
cb(err, res)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
return promise
|
||||
},
|
||||
|
||||
renderToStream: (context?: Object) => {
|
||||
const res = new PassThrough()
|
||||
run(context).catch(err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
// avoid emitting synchronously before user can
|
||||
// attach error listener
|
||||
process.nextTick(() => {
|
||||
res.emit('error', err)
|
||||
})
|
||||
}).then(app => {
|
||||
if (app) {
|
||||
const renderStream = renderer.renderToStream(app, context)
|
||||
|
||||
renderStream.on('error', err => {
|
||||
rewriteErrorTrace(err, maps)
|
||||
res.emit('error', err)
|
||||
})
|
||||
|
||||
// relay HTMLStream special events
|
||||
if (rendererOptions && rendererOptions.template) {
|
||||
renderStream.on('beforeStart', () => {
|
||||
res.emit('beforeStart')
|
||||
})
|
||||
renderStream.on('beforeEnd', () => {
|
||||
res.emit('beforeEnd')
|
||||
})
|
||||
}
|
||||
|
||||
renderStream.pipe(res)
|
||||
}
|
||||
})
|
||||
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
150
node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js
generated
vendored
Normal file
150
node_modules/vue/src/server/bundle-renderer/create-bundle-runner.js
generated
vendored
Normal file
@@ -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))
|
||||
})
|
||||
}
|
||||
}
|
45
node_modules/vue/src/server/bundle-renderer/source-map-support.js
generated
vendored
Normal file
45
node_modules/vue/src/server/bundle-renderer/source-map-support.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/* @flow */
|
||||
|
||||
const SourceMapConsumer = require('source-map').SourceMapConsumer
|
||||
|
||||
const filenameRE = /\(([^)]+\.js):(\d+):(\d+)\)$/
|
||||
|
||||
export function createSourceMapConsumers (rawMaps: Object) {
|
||||
const maps = {}
|
||||
Object.keys(rawMaps).forEach(file => {
|
||||
maps[file] = new SourceMapConsumer(rawMaps[file])
|
||||
})
|
||||
return maps
|
||||
}
|
||||
|
||||
export function rewriteErrorTrace (e: any, mapConsumers: {
|
||||
[key: string]: SourceMapConsumer
|
||||
}) {
|
||||
if (e && typeof e.stack === 'string') {
|
||||
e.stack = e.stack.split('\n').map(line => {
|
||||
return rewriteTraceLine(line, mapConsumers)
|
||||
}).join('\n')
|
||||
}
|
||||
}
|
||||
|
||||
function rewriteTraceLine (trace: string, mapConsumers: {
|
||||
[key: string]: SourceMapConsumer
|
||||
}) {
|
||||
const m = trace.match(filenameRE)
|
||||
const map = m && mapConsumers[m[1]]
|
||||
if (m != null && map) {
|
||||
const originalPosition = map.originalPositionFor({
|
||||
line: Number(m[2]),
|
||||
column: Number(m[3])
|
||||
})
|
||||
if (originalPosition.source != null) {
|
||||
const { source, line, column } = originalPosition
|
||||
const mappedPosition = `(${source.replace(/^webpack:\/\/\//, '')}:${String(line)}:${String(column)})`
|
||||
return trace.replace(filenameRE, mappedPosition)
|
||||
} else {
|
||||
return trace
|
||||
}
|
||||
} else {
|
||||
return trace
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user