Skip to content

Commit d6c0c2a

Browse files
committed
wip: compileScript
1 parent 846e316 commit d6c0c2a

File tree

7 files changed

+3157
-50
lines changed

7 files changed

+3157
-50
lines changed

Diff for: packages/compiler-sfc/src/compileScript.ts

+37-38
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import {
1010
ParserPlugin
1111
} from '@babel/parser'
1212
import { generateCodeFrame } from 'compiler/codeframe'
13-
import { camelize, capitalize, makeMap } from 'shared/util'
13+
import { camelize, capitalize, isBuiltInTag, makeMap } from 'shared/util'
14+
import { parseHTML } from 'compiler/parser/html-parser'
15+
import { baseOptions as webCompilerOptions } from 'web/compiler/options'
1416
import {
1517
Node,
1618
Declaration,
@@ -37,6 +39,10 @@ import {
3739
import { walk } from 'estree-walker'
3840
import { RawSourceMap } from 'source-map'
3941
import { warnOnce } from './warn'
42+
import { isReservedTag } from 'web/util'
43+
import { dirRE } from 'compiler/parser'
44+
import { parseText } from 'compiler/parser/text-parser'
45+
import { DEFAULT_FILENAME } from './parse'
4046

4147
// Special compiler macros
4248
const DEFINE_PROPS = 'defineProps'
@@ -52,7 +58,6 @@ const isBuiltInDir = makeMap(
5258
)
5359

5460
export interface SFCScriptCompileOptions {
55-
filename: string
5661
/**
5762
* Production mode. Used to determine whether to generate hashed CSS variables
5863
*/
@@ -82,10 +87,9 @@ export interface ImportBinding {
8287
*/
8388
export function compileScript(
8489
sfc: SFCDescriptor,
85-
options: SFCScriptCompileOptions
90+
options: SFCScriptCompileOptions = {}
8691
): SFCScriptBlock {
87-
let { script, scriptSetup, source } = sfc
88-
const { filename } = options
92+
let { filename, script, scriptSetup, source } = sfc
8993
const isProd = !!options.isProd
9094
const genSourceMap = options.sourceMap !== false
9195
let refBindings: string[] | undefined
@@ -201,10 +205,10 @@ export function compileScript(
201205

202206
// magic-string state
203207
const s = new MagicString(source)
204-
const startOffset = scriptSetup.loc.start.offset
205-
const endOffset = scriptSetup.loc.end.offset
206-
const scriptStartOffset = script && script.loc.start.offset
207-
const scriptEndOffset = script && script.loc.end.offset
208+
const startOffset = scriptSetup.start
209+
const endOffset = scriptSetup.end
210+
const scriptStartOffset = script && script.start
211+
const scriptEndOffset = script && script.end
208212

209213
function helper(key: string): string {
210214
helperImports.add(key)
@@ -1211,7 +1215,7 @@ export function compileScript(
12111215

12121216
// 11. finalize default export
12131217
let runtimeOptions = ``
1214-
if (!hasDefaultExportName && filename) {
1218+
if (!hasDefaultExportName && filename && filename !== DEFAULT_FILENAME) {
12151219
const match = filename.match(/([^/\\]+)\.\w+$/)
12161220
if (match) {
12171221
runtimeOptions += `\n __name: '${match[1]}',`
@@ -1828,44 +1832,39 @@ function getObjectOrArrayExpressionKeys(value: Node): string[] {
18281832
const templateUsageCheckCache = new LRU<string, string>(512)
18291833

18301834
function resolveTemplateUsageCheckString(sfc: SFCDescriptor) {
1831-
const { content, ast } = sfc.template!
1835+
const { content } = sfc.template!
18321836
const cached = templateUsageCheckCache.get(content)
18331837
if (cached) {
18341838
return cached
18351839
}
18361840

18371841
let code = ''
1838-
transform(createRoot([ast]), {
1839-
nodeTransforms: [
1840-
node => {
1841-
if (node.type === NodeTypes.ELEMENT) {
1842-
if (
1843-
!parserOptions.isNativeTag!(node.tag) &&
1844-
!parserOptions.isBuiltInComponent!(node.tag)
1845-
) {
1846-
code += `,${camelize(node.tag)},${capitalize(camelize(node.tag))}`
1842+
1843+
parseHTML(content, {
1844+
...webCompilerOptions,
1845+
start(tag, attrs) {
1846+
if (!isBuiltInTag(tag) && !isReservedTag(tag)) {
1847+
code += `,${camelize(tag)},${capitalize(camelize(tag))}`
1848+
}
1849+
for (let i = 0; i < attrs.length; i++) {
1850+
const { name, value } = attrs[i]
1851+
if (dirRE.test(name)) {
1852+
const baseName = name.replace(dirRE, '')
1853+
if (!isBuiltInDir(baseName)) {
1854+
code += `,v${capitalize(camelize(baseName))}`
18471855
}
1848-
for (let i = 0; i < node.props.length; i++) {
1849-
const prop = node.props[i]
1850-
if (prop.type === NodeTypes.DIRECTIVE) {
1851-
if (!isBuiltInDir(prop.name)) {
1852-
code += `,v${capitalize(camelize(prop.name))}`
1853-
}
1854-
if (prop.exp) {
1855-
code += `,${processExp(
1856-
(prop.exp as SimpleExpressionNode).content,
1857-
prop.name
1858-
)}`
1859-
}
1860-
}
1856+
if (value) {
1857+
code += `,${processExp(value, baseName)}`
18611858
}
1862-
} else if (node.type === NodeTypes.INTERPOLATION) {
1863-
code += `,${processExp(
1864-
(node.content as SimpleExpressionNode).content
1865-
)}`
18661859
}
18671860
}
1868-
]
1861+
},
1862+
chars(text) {
1863+
const res = parseText(text)
1864+
if (res) {
1865+
code += `,${processExp(res.expression)}`
1866+
}
1867+
}
18691868
})
18701869

18711870
code += ';'

Diff for: packages/compiler-sfc/src/parse.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
import hash from 'hash-sum'
1010
import LRU from 'lru-cache'
1111

12+
export const DEFAULT_FILENAME = 'anonymous.vue'
13+
1214
const cache = new LRU<string, SFCDescriptor>(100)
1315

1416
const splitRE = /\r?\n/g
@@ -26,9 +28,9 @@ export interface ParseOptions {
2628
export function parse(options: ParseOptions): SFCDescriptor {
2729
const {
2830
source,
29-
filename = '',
31+
filename = DEFAULT_FILENAME,
3032
compiler,
31-
compilerParseOptions = { pad: 'line' } as VueTemplateCompilerParseOptions,
33+
compilerParseOptions = { pad: false } as VueTemplateCompilerParseOptions,
3234
sourceRoot = '',
3335
needMap = true
3436
} = options
@@ -49,6 +51,8 @@ export function parse(options: ParseOptions): SFCDescriptor {
4951
output = parseComponent(source, compilerParseOptions)
5052
}
5153

54+
output.filename = filename
55+
5256
if (needMap) {
5357
if (output.script && !output.script.src) {
5458
output.script.map = generateSourceMap(
@@ -73,6 +77,7 @@ export function parse(options: ParseOptions): SFCDescriptor {
7377
})
7478
}
7579
}
80+
7681
cache.set(cacheKey, output)
7782
return output
7883
}

Diff for: packages/compiler-sfc/src/parseComponent.ts

+10-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { makeMap } from 'shared/util'
44
import { ASTAttr, WarningMessage } from 'types/compiler'
55
import { BindingMetadata, RawSourceMap } from './types'
66
import { hmrShouldReload, ImportBinding } from './compileScript'
7+
import { DEFAULT_FILENAME } from './parse'
78

89
const splitRE = /\r?\n/g
910
const replaceRE = /./g
@@ -42,6 +43,7 @@ export interface SFCScriptBlock extends SFCBlock {
4243

4344
export interface SFCDescriptor {
4445
source: string
46+
filename: string
4547
template: SFCBlock | null
4648
script: SFCScriptBlock | null
4749
scriptSetup: SFCScriptBlock | null
@@ -70,11 +72,12 @@ export interface VueTemplateCompilerParseOptions {
7072
* Parse a single-file component (*.vue) file into an SFC Descriptor Object.
7173
*/
7274
export function parseComponent(
73-
content: string,
75+
source: string,
7476
options: VueTemplateCompilerParseOptions = {}
7577
): SFCDescriptor {
7678
const sfc: SFCDescriptor = {
77-
source: content,
79+
source,
80+
filename: DEFAULT_FILENAME,
7881
template: null,
7982
script: null,
8083
scriptSetup: null, // TODO
@@ -167,8 +170,8 @@ export function parseComponent(
167170
function end(tag: string, start: number) {
168171
if (depth === 1 && currentBlock) {
169172
currentBlock.end = start
170-
let text = content.slice(currentBlock.start, currentBlock.end)
171-
if (options.deindent !== false) {
173+
let text = source.slice(currentBlock.start, currentBlock.end)
174+
if (options.deindent) {
172175
text = deindent(text)
173176
}
174177
// pad content so that linters and pre-processors can output correct
@@ -184,15 +187,15 @@ export function parseComponent(
184187

185188
function padContent(block: SFCBlock, pad: true | 'line' | 'space') {
186189
if (pad === 'space') {
187-
return content.slice(0, block.start).replace(replaceRE, ' ')
190+
return source.slice(0, block.start).replace(replaceRE, ' ')
188191
} else {
189-
const offset = content.slice(0, block.start).split(splitRE).length
192+
const offset = source.slice(0, block.start).split(splitRE).length
190193
const padChar = block.type === 'script' && !block.lang ? '//\n' : '\n'
191194
return Array(offset).join(padChar)
192195
}
193196
}
194197

195-
parseHTML(content, {
198+
parseHTML(source, {
196199
warn,
197200
start,
198201
end,

0 commit comments

Comments
 (0)