Skip to content

Commit

Permalink
feat(add): sfc->compile doCompileTemplate
Browse files Browse the repository at this point in the history
  • Loading branch information
gcclll committed Dec 19, 2020
1 parent 1b2965f commit 7b49db4
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 2 deletions.
105 changes: 103 additions & 2 deletions packages/compiler-sfc/src/compileTemplate.ts
Expand Up @@ -2,13 +2,26 @@ import {
CodegenResult,
CompilerError,
CompilerOptions,
NodeTransform,
ParserOptions,
RootNode
} from '@vue/compiler-core'
import { RawSourceMap } from 'source-map'
import * as CompilerDOM from '@vue/compiler-dom'
import { AssetURLOptions, AssetURLTagConfig } from './templateTransformAssetUrl'
import {
AssetURLOptions,
AssetURLTagConfig,
createAssetUrlTransformWithOptions,
normalizeOptions,
transformAssetUrl
} from './templateTransformAssetUrl'
import consolidate from 'consolidate'
import { isObject } from '@vue/shared'
import { warnOnce } from './warn'
import {
createSrcsetTransformWithOptions,
transformSrcset
} from './templateTransformSrcset'

export interface TemplateCompiler {
compile(template: string, options: CompilerOptions): CodegenResult
Expand Down Expand Up @@ -127,5 +140,93 @@ function doCompileTemplate({
compilerOptions = {},
transformAssetUrls
}: SFCTemplateCompileOptions): SFCTemplateCompileResults {
return {} as SFCTemplateCompileResults
const errors: CompilerError[] = []

// 下面是收集 node transforms -> compiler-core transform 时使用
let nodeTransforms: NodeTransform[] = []
if (isObject(transformAssetUrls)) {
const assetOptions = normalizeOptions(transformAssetUrls)
nodeTransforms = [
createAssetUrlTransformWithOptions(assetOptions),
createSrcsetTransformWithOptions(assetOptions)
]
} else if (transformAssetUrls !== false) {
nodeTransforms = [transformAssetUrl, transformSrcset]
}

if (ssr && !ssrCssVars) {
warnOnce(
`compileTemplate is called with \`ssr: true\` but no ` +
`corresponding \`cssVars\` option.\`.`
)
}

if (!id) {
warnOnce(`compileTemplate now requires the \`id\` option.\`.`)
id = ''
}

const shortId = id.replace(/^data-v-/, '')
const longId = `data-v-${shortId}`

let { code, ast, preamble, map } = compiler.compile(source, {
mode: 'module',
prefixIdentifiers: true,
hoistStatic: true,
cacheHandlers: true,
ssrCssVars:
ssr && ssrCssVars && ssrCssVars.length
? '' /* TODO genCssVarsFromList(ssrCssVars, shortId, isProd) */
: '',
// css 局部使用,加上对应的唯一 id
scopeId: scoped ? longId : undefined,
...compilerOptions,
nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
filename,
sourceMap: true,
onError: e => errors.push(e)
})

// inMap should be the map produced by ./parse.ts which is a simple line-only
// mapping. If it is present, we need to adjust the final map and errors to
// reflect the original line numbers.
if (inMap) {
if (map) {
map = mapLines(inMap, map)
}

if (errors.length) {
patchErrors(errors, source, inMap)
}
}

return { code, ast, preamble, source, errors, tips: [], map }
}

function mapLines(oldMap: RawSourceMap, newMap: RawSourceMap): RawSourceMap {
if (!oldMap) return newMap
if (!newMap) return oldMap

// TODO
return oldMap
}

function patchErrors(
errors: CompilerError[],
source: string,
inMap: RawSourceMap
) {
const originalSource = inMap.sourcesContent![0]
const offset = originalSource.indexOf(source)
const lineOffset = originalSource.slice(0, offset).split(/\r?\n/).length - 1
errors.forEach(err => {
if (err.loc) {
err.loc.start.line += lineOffset
err.loc.start.offset += offset
if (err.loc.end !== err.loc.start) {
err.loc.end.line += lineOffset
err.loc.end.offset += offset
}
}
})
}
55 changes: 55 additions & 0 deletions packages/compiler-sfc/src/templateTransformAssetUrl.ts
@@ -1,3 +1,6 @@
import { NodeTransform } from '@vue/compiler-core'
import { isArray } from '@vue/shared'

export interface AssetURLTagConfig {
[name: string]: string[]
}
Expand All @@ -14,3 +17,55 @@ export interface AssetURLOptions {
includeAbsolute?: boolean
tags?: AssetURLTagConfig
}

export const defaultAssetUrlOptions: Required<AssetURLOptions> = {
base: null,
includeAbsolute: false,
tags: {
video: ['src', 'poster'],
source: ['src'],
img: ['src'],
image: ['xlink:href', 'href'],
use: ['xlink:href', 'href']
}
}

// 合并选项
export const normalizeOptions = (
options: AssetURLOptions | AssetURLTagConfig
): Required<AssetURLOptions> => {
if (Object.keys(options).some(key => isArray((options as any)[key]))) {
// legacy option format which directly passes in tags config
return {
...defaultAssetUrlOptions,
tags: options as any
}
}

return {
...defaultAssetUrlOptions,
...options
}
}

export const createAssetUrlTransformWithOptions = (
options: Required<AssetURLOptions>
): NodeTransform => {
return (node, context) =>
(transformAssetUrl as Function)(node, context, options)
}

/**
* A `@vue/compiler-core` plugin that transforms relative asset urls into
* either imports or absolute urls.
*
* ``` js
* // Before
* createVNode('img', { src: './logo.png' })
*
* // After
* import _imports_0 from './logo.png'
* createVNode('img', { src: _imports_0 })
* ```
*/
export const transformAssetUrl: NodeTransform = () => {}
18 changes: 18 additions & 0 deletions packages/compiler-sfc/src/templateTransformSrcset.ts
@@ -0,0 +1,18 @@
import { NodeTransform } from '@vue/compiler-dom'
import {
AssetURLOptions,
defaultAssetUrlOptions
} from './templateTransformAssetUrl'

export const createSrcsetTransformWithOptions = (
options: Required<AssetURLOptions>
): NodeTransform => {
return (node, context) =>
(transformSrcset as Function)(node, context, options)
}

export const transformSrcset: NodeTransform = (
node,
context,
options: Required<AssetURLOptions> = defaultAssetUrlOptions
) => {}

0 comments on commit 7b49db4

Please sign in to comment.