mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-04 21:17:55 +08:00
refactor compiler creation
This commit is contained in:
parent
f66028b9cd
commit
5d12d52710
@ -3,11 +3,11 @@
|
||||
import { parse } from './parser/index'
|
||||
import { optimize } from './optimizer'
|
||||
import { generate } from './codegen/index'
|
||||
import { detectErrors } from './error-detector'
|
||||
import { extend, noop } from 'shared/util'
|
||||
import { warn, tip } from 'core/util/debug'
|
||||
|
||||
/**
|
||||
* Compile a template.
|
||||
*/
|
||||
export function compile (
|
||||
function baseCompile (
|
||||
template: string,
|
||||
options: CompilerOptions
|
||||
): CompiledResult {
|
||||
@ -20,3 +20,140 @@ export function compile (
|
||||
staticRenderFns: code.staticRenderFns
|
||||
}
|
||||
}
|
||||
|
||||
function makeFunction (code, errors) {
|
||||
try {
|
||||
return new Function(code)
|
||||
} catch (err) {
|
||||
errors.push({ err, code })
|
||||
return noop
|
||||
}
|
||||
}
|
||||
|
||||
export function createCompiler (baseOptions: CompilerOptions) {
|
||||
const functionCompileCache: {
|
||||
[key: string]: CompiledFunctionResult;
|
||||
} = Object.create(null)
|
||||
|
||||
function compile (
|
||||
template: string,
|
||||
options?: CompilerOptions
|
||||
): CompiledResult {
|
||||
const finalOptions = Object.create(baseOptions)
|
||||
const errors = []
|
||||
const tips = []
|
||||
finalOptions.warn = (msg, tip) => {
|
||||
(tip ? tips : errors).push(msg)
|
||||
}
|
||||
|
||||
if (options) {
|
||||
// merge custom modules
|
||||
if (options.modules) {
|
||||
finalOptions.modules = (baseOptions.modules || []).concat(options.modules)
|
||||
}
|
||||
// merge custom directives
|
||||
if (options.directives) {
|
||||
finalOptions.directives = extend(
|
||||
Object.create(baseOptions.directives),
|
||||
options.directives
|
||||
)
|
||||
}
|
||||
// copy other options
|
||||
for (const key in options) {
|
||||
if (key !== 'modules' && key !== 'directives') {
|
||||
finalOptions[key] = options[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const compiled = baseCompile(template, finalOptions)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
errors.push.apply(errors, detectErrors(compiled.ast))
|
||||
}
|
||||
compiled.errors = errors
|
||||
compiled.tips = tips
|
||||
return compiled
|
||||
}
|
||||
|
||||
function compileToFunctions (
|
||||
template: string,
|
||||
options?: CompilerOptions,
|
||||
vm?: Component
|
||||
): CompiledFunctionResult {
|
||||
options = options || {}
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// detect possible CSP restriction
|
||||
try {
|
||||
new Function('return 1')
|
||||
} catch (e) {
|
||||
if (e.toString().match(/unsafe-eval|CSP/)) {
|
||||
warn(
|
||||
'It seems you are using the standalone build of Vue.js in an ' +
|
||||
'environment with Content Security Policy that prohibits unsafe-eval. ' +
|
||||
'The template compiler cannot work in this environment. Consider ' +
|
||||
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
|
||||
'templates into render functions.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check cache
|
||||
const key = options.delimiters
|
||||
? String(options.delimiters) + template
|
||||
: template
|
||||
if (functionCompileCache[key]) {
|
||||
return functionCompileCache[key]
|
||||
}
|
||||
|
||||
// compile
|
||||
const compiled = compile(template, options)
|
||||
|
||||
// check compilation errors/tips
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (compiled.errors && compiled.errors.length) {
|
||||
warn(
|
||||
`Error compiling template:\n\n${template}\n\n` +
|
||||
compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
|
||||
vm
|
||||
)
|
||||
}
|
||||
if (compiled.tips && compiled.tips.length) {
|
||||
compiled.tips.forEach(msg => tip(msg, vm))
|
||||
}
|
||||
}
|
||||
|
||||
// turn code into functions
|
||||
const res = {}
|
||||
const fnGenErrors = []
|
||||
res.render = makeFunction(compiled.render, fnGenErrors)
|
||||
const l = compiled.staticRenderFns.length
|
||||
res.staticRenderFns = new Array(l)
|
||||
for (let i = 0; i < l; i++) {
|
||||
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors)
|
||||
}
|
||||
|
||||
// check function generation errors.
|
||||
// this should only happen if there is a bug in the compiler itself.
|
||||
// mostly for codegen development use
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
|
||||
warn(
|
||||
`Failed to generate render function:\n\n` +
|
||||
fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
|
||||
vm
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (functionCompileCache[key] = res)
|
||||
}
|
||||
|
||||
return {
|
||||
compile,
|
||||
compileToFunctions
|
||||
}
|
||||
}
|
||||
|
@ -1,151 +1,30 @@
|
||||
/* @flow */
|
||||
|
||||
import { isUnaryTag } from './util'
|
||||
import { warn, tip } from 'core/util/debug'
|
||||
import { detectErrors } from 'compiler/error-detector'
|
||||
import { compile as baseCompile } from 'compiler/index'
|
||||
import { extend, genStaticKeys, noop } from 'shared/util'
|
||||
import { isReservedTag, mustUseProp, getTagNamespace, isPreTag } from '../util/index'
|
||||
import { genStaticKeys } from 'shared/util'
|
||||
import { createCompiler } from 'compiler/index'
|
||||
|
||||
import modules from './modules/index'
|
||||
import directives from './directives/index'
|
||||
|
||||
const cache: { [key: string]: CompiledFunctionResult } = Object.create(null)
|
||||
import {
|
||||
isPreTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
getTagNamespace
|
||||
} from '../util/index'
|
||||
|
||||
export const baseOptions: CompilerOptions = {
|
||||
expectHTML: true,
|
||||
modules,
|
||||
staticKeys: genStaticKeys(modules),
|
||||
directives,
|
||||
isReservedTag,
|
||||
isPreTag,
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
getTagNamespace,
|
||||
isPreTag
|
||||
staticKeys: genStaticKeys(modules)
|
||||
}
|
||||
|
||||
export function compile (
|
||||
template: string,
|
||||
options?: CompilerOptions
|
||||
): CompiledResult {
|
||||
const finalOptions = Object.create(baseOptions)
|
||||
const errors = []
|
||||
const tips = []
|
||||
finalOptions.warn = (msg, tip) => {
|
||||
(tip ? tips : errors).push(msg)
|
||||
}
|
||||
|
||||
if (options) {
|
||||
// merge custom modules
|
||||
if (options.modules) {
|
||||
finalOptions.modules = (baseOptions.modules || []).concat(options.modules)
|
||||
}
|
||||
// merge custom directives
|
||||
if (options.directives) {
|
||||
finalOptions.directives = extend(
|
||||
Object.create(baseOptions.directives),
|
||||
options.directives
|
||||
)
|
||||
}
|
||||
// copy other options
|
||||
for (const key in options) {
|
||||
if (key !== 'modules' && key !== 'directives') {
|
||||
finalOptions[key] = options[key]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const compiled = baseCompile(template, finalOptions)
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
errors.push.apply(errors, detectErrors(compiled.ast))
|
||||
}
|
||||
compiled.errors = errors
|
||||
compiled.tips = tips
|
||||
return compiled
|
||||
}
|
||||
|
||||
export function compileToFunctions (
|
||||
template: string,
|
||||
options?: CompilerOptions,
|
||||
vm?: Component
|
||||
): CompiledFunctionResult {
|
||||
options = extend({}, options)
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// detect possible CSP restriction
|
||||
try {
|
||||
new Function('return 1')
|
||||
} catch (e) {
|
||||
if (e.toString().match(/unsafe-eval|CSP/)) {
|
||||
warn(
|
||||
'It seems you are using the standalone build of Vue.js in an ' +
|
||||
'environment with Content Security Policy that prohibits unsafe-eval. ' +
|
||||
'The template compiler cannot work in this environment. Consider ' +
|
||||
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
|
||||
'templates into render functions.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check cache
|
||||
const key = options.delimiters
|
||||
? String(options.delimiters) + template
|
||||
: template
|
||||
if (cache[key]) {
|
||||
return cache[key]
|
||||
}
|
||||
|
||||
// compile
|
||||
const compiled = compile(template, options)
|
||||
|
||||
// check compilation errors/tips
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (compiled.errors && compiled.errors.length) {
|
||||
warn(
|
||||
`Error compiling template:\n\n${template}\n\n` +
|
||||
compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
|
||||
vm
|
||||
)
|
||||
}
|
||||
if (compiled.tips && compiled.tips.length) {
|
||||
compiled.tips.forEach(msg => tip(msg, vm))
|
||||
}
|
||||
}
|
||||
|
||||
// turn code into functions
|
||||
const res = {}
|
||||
const fnGenErrors = []
|
||||
res.render = makeFunction(compiled.render, fnGenErrors)
|
||||
const l = compiled.staticRenderFns.length
|
||||
res.staticRenderFns = new Array(l)
|
||||
for (let i = 0; i < l; i++) {
|
||||
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors)
|
||||
}
|
||||
|
||||
// check function generation errors.
|
||||
// this should only happen if there is a bug in the compiler itself.
|
||||
// mostly for codegen development use
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
|
||||
warn(
|
||||
`Failed to generate render function:\n\n` +
|
||||
fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
|
||||
vm
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (cache[key] = res)
|
||||
}
|
||||
|
||||
function makeFunction (code, errors) {
|
||||
try {
|
||||
return new Function(code)
|
||||
} catch (err) {
|
||||
errors.push({ err, code })
|
||||
return noop
|
||||
}
|
||||
}
|
||||
const { compile, compileToFunctions } = createCompiler(baseOptions)
|
||||
export { compile, compileToFunctions }
|
||||
|
@ -1,93 +1,28 @@
|
||||
/* @flow */
|
||||
|
||||
import { extend, genStaticKeys, noop } from 'shared/util'
|
||||
import { warn } from 'core/util/debug'
|
||||
import { compile as baseCompile } from 'compiler/index'
|
||||
import { detectErrors } from 'compiler/error-detector'
|
||||
import { genStaticKeys } from 'shared/util'
|
||||
import { createCompiler } from 'compiler/index'
|
||||
|
||||
import modules from './modules/index'
|
||||
import directives from './directives/index'
|
||||
|
||||
import {
|
||||
isReservedTag, isUnaryTag,
|
||||
mustUseProp, getTagNamespace
|
||||
} from '../util/index'
|
||||
|
||||
const cache: { [key: string]: CompiledFunctionResult } = Object.create(null)
|
||||
|
||||
export const baseOptions: CompilerOptions = {
|
||||
preserveWhitespace: false,
|
||||
modules,
|
||||
staticKeys: genStaticKeys(modules),
|
||||
directives,
|
||||
isReservedTag,
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
getTagNamespace
|
||||
} from '../util/index'
|
||||
|
||||
export const baseOptions: CompilerOptions = {
|
||||
modules,
|
||||
directives,
|
||||
isUnaryTag,
|
||||
mustUseProp,
|
||||
isReservedTag,
|
||||
getTagNamespace,
|
||||
preserveWhitespace: false,
|
||||
staticKeys: genStaticKeys(modules)
|
||||
}
|
||||
|
||||
export function compile (
|
||||
template: string,
|
||||
options?: CompilerOptions
|
||||
): CompiledResult {
|
||||
options = options
|
||||
? extend(extend({}, baseOptions), options)
|
||||
: baseOptions
|
||||
return baseCompile(template, options)
|
||||
}
|
||||
|
||||
export function compileToFunctions (
|
||||
template: string,
|
||||
options?: CompilerOptions,
|
||||
vm?: Component
|
||||
): CompiledFunctionResult {
|
||||
const _warn = (options && options.warn) || warn
|
||||
// detect possible CSP restriction
|
||||
/* istanbul ignore if */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
try {
|
||||
new Function('return 1')
|
||||
} catch (e) {
|
||||
if (e.toString().match(/unsafe-eval|CSP/)) {
|
||||
_warn(
|
||||
'It seems you are using the standalone build of Vue.js in an ' +
|
||||
'environment with Content Security Policy that prohibits unsafe-eval. ' +
|
||||
'The template compiler cannot work in this environment. Consider ' +
|
||||
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
|
||||
'templates into render functions.'
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
const key = options && options.delimiters
|
||||
? String(options.delimiters) + template
|
||||
: template
|
||||
if (cache[key]) {
|
||||
return cache[key]
|
||||
}
|
||||
const res = {}
|
||||
const compiled = compile(template, options)
|
||||
res.render = makeFunction(compiled.render)
|
||||
const l = compiled.staticRenderFns.length
|
||||
res.staticRenderFns = new Array(l)
|
||||
for (let i = 0; i < l; i++) {
|
||||
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i])
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (res.render === noop || res.staticRenderFns.some(fn => fn === noop)) {
|
||||
_warn(
|
||||
`failed to compile template:\n\n${template}\n\n` +
|
||||
detectErrors(compiled.ast).join('\n') +
|
||||
'\n\n',
|
||||
vm
|
||||
)
|
||||
}
|
||||
}
|
||||
return (cache[key] = res)
|
||||
}
|
||||
|
||||
function makeFunction (code) {
|
||||
try {
|
||||
return new Function(code)
|
||||
} catch (e) {
|
||||
return noop
|
||||
}
|
||||
}
|
||||
const { compile, compileToFunctions } = createCompiler(baseOptions)
|
||||
export { compile, compileToFunctions }
|
||||
|
Loading…
Reference in New Issue
Block a user