Skip to content

Commit f103563

Browse files
committed
init
0 parents  commit f103563

18 files changed

+4535
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.DS_Store
2+
node_modules
3+
*.log
4+
dist

.npmignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
test
2+
jest.config.js
3+
tsconfig.json
4+
*.log
5+
*.lock

README.md

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# @vue/component-compiler-utils
2+
3+
> Lower level utilities for compiling Vue single file components
4+
5+
This package contains lower level utilities that you can use if you are writing a plugin / transform for a bundler or module system that compiles Vue single file components into JavaScript. It is used in [vue-loader](https://github.com/vuejs/vue-loader) version 15 and above.
6+
7+
The API surface is intentionally minimal - the goal is to reuse as much as possible while being as flexible as possible.
8+
9+
## API
10+
11+
### parse(ParseOptions): SFCDescriptor
12+
13+
Parse raw single file component source into a descriptor with source maps.
14+
15+
``` ts
16+
interface ParseOptions {
17+
source: string
18+
filename?: string
19+
sourceRoot?: string
20+
needMap?: boolean
21+
}
22+
23+
interface SFCDescriptor {
24+
template?: SFCBlock
25+
script?: SFCBlock
26+
styles: SFCBlock[]
27+
customBlocks: SFCCustomBlock[]
28+
}
29+
30+
interface SFCCustomBlock {
31+
type: string
32+
content: string
33+
attrs: { [key: string]: string }
34+
start: number
35+
end: number
36+
map: RawSourceMap
37+
}
38+
39+
interface SFCBlock extends SFCCustomBlock {
40+
lang?: string
41+
src?: string
42+
scoped?: boolean
43+
module?: string | boolean
44+
}
45+
```
46+
47+
### compileTemplate(TemplateCompileOptions): TemplateCompileResults
48+
49+
Takes raw template source and compile it into JavaScript code. The actual compiler (`vue-template-compiler`) must be passed so that the specific version used can be determined by the end user.
50+
51+
It can also optionally perform pre-processing for any templating engine supported by [consolidate](https://github.com/tj/consolidate.js/).
52+
53+
``` ts
54+
interface TemplateCompileOptions {
55+
source: string
56+
filename: string
57+
58+
// See https://github.com/vuejs/vue/tree/dev/packages/vue-template-compiler
59+
compiler: VueTemplateCompiler
60+
compilerOptions?: VueTemplateCompilerOptions
61+
62+
// Template preprocessor
63+
preprocessLang?: string
64+
preprocessOptions?: any
65+
66+
// Transform asset urls found in the template into `require()` calls
67+
// This is off by default. If set to true, the default value is
68+
// {
69+
// video: ['src', 'poster'],
70+
// source: 'src',
71+
// img: 'src',
72+
// image: 'xlink:href'
73+
// }
74+
transformAssetUrls?: AssetURLOptions | boolean
75+
76+
// For vue-template-es2015-compiler, which is a fork of Buble
77+
transpileOptions?: any
78+
79+
isProduction?: boolean // default: false
80+
isFunctional?: boolean // default: false
81+
optimizeSSR?: boolean // default: false
82+
}
83+
84+
interface TemplateCompileResult {
85+
code: string
86+
source: string
87+
tips: string[]
88+
errors: string[]
89+
}
90+
91+
interface AssetURLOptions {
92+
[name: string]: string | string[]
93+
}
94+
```
95+
96+
#### Handling the Output
97+
98+
The resulting JavaScript code will look like this:
99+
100+
``` js
101+
var render = function (h) { /* ... */}
102+
var staticRenderFns = [function (h) { /* ... */}, function (h) { /* ... */}]
103+
```
104+
105+
It **does NOT** assume any module system. It is your responsibility to handle the exports, if needed.
106+
107+
### compileStyle(StyleCompileOptions)
108+
109+
Take input raw CSS and applies scoped CSS transform. It does NOT handle pre-processors. If the component doesn't use scoped CSS then this step can be skipped.
110+
111+
``` ts
112+
interface StyleCompileOptions {
113+
source: string
114+
filename: string
115+
id: string
116+
map?: any
117+
scoped?: boolean
118+
trim?: boolean
119+
}
120+
121+
interface StyleCompileResults {
122+
code: string
123+
map: any | void
124+
rawResult: LazyResult | void // raw lazy result from PostCSS
125+
errors: string[]
126+
}
127+
```

jest.config.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module.exports = {
2+
moduleFileExtensions: ['ts', 'js', 'json'],
3+
transform: {
4+
'^.+\\.jsx?$': 'babel-jest',
5+
'^.+\\.tsx?$': '<rootDir>/node_modules/ts-jest/preprocessor.js'
6+
}
7+
}

lib/compileStyle.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { ProcessOptions, LazyResult } from 'postcss'
2+
import postcss = require('postcss')
3+
import trimPlugin from './stylePlugins/trim'
4+
import scopedPlugin from './stylePlugins/scoped'
5+
6+
export interface StyleCompileOptions {
7+
source: string
8+
filename: string
9+
id: string
10+
map?: any
11+
scoped?: boolean
12+
trim?: boolean
13+
}
14+
15+
export interface StyleCompileResults {
16+
code: string
17+
map: any | void
18+
rawResult: LazyResult | void
19+
errors: string[]
20+
}
21+
22+
export function compileStyle (
23+
options: StyleCompileOptions
24+
): StyleCompileResults {
25+
const {
26+
source,
27+
filename,
28+
id,
29+
map,
30+
scoped = true,
31+
trim = true
32+
} = options
33+
34+
const plugins = []
35+
if (trim) {
36+
plugins.push(trimPlugin())
37+
}
38+
if (scoped) {
39+
plugins.push(scopedPlugin(id))
40+
}
41+
42+
const postCSSOptions: ProcessOptions = {
43+
to: filename,
44+
from: filename
45+
}
46+
if (map) {
47+
postCSSOptions.map = {
48+
inline: false,
49+
annotation: false,
50+
prev: map
51+
}
52+
}
53+
54+
let result, code, outMap
55+
const errors = []
56+
try {
57+
result = postcss(plugins).process(source, postCSSOptions)
58+
// force synchronous transform (we know we only have sync plugins)
59+
code = result.css
60+
outMap = result.map
61+
} catch (e) {
62+
errors.push(e)
63+
}
64+
65+
return {
66+
code: code || ``,
67+
map: outMap && outMap.toJSON(),
68+
errors,
69+
rawResult: result
70+
}
71+
}

lib/compileTemplate.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import {
2+
VueTemplateCompiler,
3+
VueTemplateCompilerOptions
4+
} from './types'
5+
6+
import assetUrlsModule, { AssetURLOptions } from './templateCompilerModules/assetUrl'
7+
import srcsetModule from './templateCompilerModules/srcset'
8+
9+
const prettier = require('prettier')
10+
const consolidate = require('consolidate')
11+
const transpile = require('vue-template-es2015-compiler')
12+
13+
export interface TemplateCompileOptions {
14+
source: string
15+
filename: string
16+
compiler: VueTemplateCompiler
17+
compilerOptions?: VueTemplateCompilerOptions
18+
transformAssetUrls?: AssetURLOptions | boolean
19+
preprocessLang?: string
20+
preprocessOptions?: any
21+
transpileOptions?: any
22+
isProduction?: boolean
23+
isFunctional?: boolean
24+
optimizeSSR?: boolean
25+
}
26+
27+
export interface TemplateCompileResult {
28+
code: string
29+
source: string
30+
tips: string[]
31+
errors: string[]
32+
}
33+
34+
export function compileTemplate (
35+
options: TemplateCompileOptions
36+
): TemplateCompileResult {
37+
const { preprocessLang } = options
38+
const preprocessor = preprocessLang && consolidate[preprocessLang]
39+
if (preprocessor) {
40+
return actuallyCompile(Object.assign({}, options, {
41+
source: preprocess(options, preprocessor)
42+
}))
43+
} else {
44+
return actuallyCompile(options)
45+
}
46+
}
47+
48+
function preprocess (
49+
options: TemplateCompileOptions,
50+
preprocessor: any
51+
): string {
52+
const {
53+
source,
54+
filename,
55+
preprocessOptions
56+
} = options
57+
58+
const finalPreprocessOptions = Object.assign({
59+
filename
60+
}, preprocessOptions)
61+
62+
// Consolidate exposes a callback based API, but the callback is in fact
63+
// called synchronously for most templating engines. In our case, we have to
64+
// expose a synchronous API so that it is usable in Jest transforms (which
65+
// have to be sync because they are applied via Node.js require hooks)
66+
let res: any, err
67+
preprocessor.render(
68+
source,
69+
finalPreprocessOptions,
70+
(_err: Error | null, _res: string) => {
71+
if (_err) err = _err
72+
res = _res
73+
}
74+
)
75+
76+
if (err) throw err
77+
return res
78+
}
79+
80+
function actuallyCompile (
81+
options: TemplateCompileOptions
82+
): TemplateCompileResult {
83+
const {
84+
source,
85+
compiler,
86+
compilerOptions = {},
87+
transpileOptions = {},
88+
transformAssetUrls,
89+
isProduction = process.env.NODE_ENV === 'production',
90+
isFunctional = false,
91+
optimizeSSR = false
92+
} = options
93+
94+
const compile = optimizeSSR && compiler.ssrCompile
95+
? compiler.ssrCompile
96+
: compiler.compile
97+
98+
let finalCompilerOptions = compilerOptions
99+
if (transformAssetUrls) {
100+
const builtInModules = [
101+
transformAssetUrls === true
102+
? assetUrlsModule()
103+
: assetUrlsModule(transformAssetUrls),
104+
srcsetModule()
105+
]
106+
finalCompilerOptions = Object.assign({}, compilerOptions, {
107+
modules: [...builtInModules, ...compilerOptions.modules || []]
108+
})
109+
}
110+
111+
const {
112+
render,
113+
staticRenderFns,
114+
tips,
115+
errors
116+
} = compile(source, finalCompilerOptions)
117+
118+
if (errors && errors.length) {
119+
return {
120+
code: (
121+
`var render = function () {}\n` +
122+
`var staticRenderFns = []\n`
123+
),
124+
source,
125+
tips,
126+
errors
127+
}
128+
} else {
129+
const finalTranspileOptions = Object.assign({}, transpileOptions, {
130+
transforms: Object.assign({}, transpileOptions.transforms, {
131+
stripWithFunctional: isFunctional
132+
})
133+
})
134+
135+
const toFunction = (code: string): string => {
136+
return `function (${isFunctional ? `_h,_vm` : ``}) {${code}}`
137+
}
138+
139+
// transpile code with vue-template-es2015-compiler, which is a forked
140+
// version of Buble that applies ES2015 transforms + stripping `with` usage
141+
let code = transpile(
142+
`var render = ${toFunction(render)}\n` +
143+
`var staticRenderFns = [${staticRenderFns.map(toFunction)}]`,
144+
finalTranspileOptions
145+
) + `\n`
146+
147+
if (!isProduction) {
148+
// mark with stripped (this enables Vue to use correct runtime proxy
149+
// detection)
150+
code += `render._withStripped = true`
151+
code = prettier.format(code, { semi: false })
152+
}
153+
154+
return {
155+
code,
156+
source,
157+
tips,
158+
errors
159+
}
160+
}
161+
}

lib/genId.ts

Whitespace-only changes.

0 commit comments

Comments
 (0)