Skip to content

Commit ce0bbe0

Browse files
committed
feat: support component-level compilerOptions when using runtime compiler
- The `delimiters` component option is deprecated. Use `compilerOptions.delimiters` instead.
1 parent e486254 commit ce0bbe0

File tree

4 files changed

+142
-7
lines changed

4 files changed

+142
-7
lines changed

packages/runtime-core/src/component.ts

+19-5
Original file line numberDiff line numberDiff line change
@@ -578,6 +578,13 @@ function setupStatefulComponent(
578578
validateDirectiveName(names[i])
579579
}
580580
}
581+
if (Component.compilerOptions && isRuntimeOnly()) {
582+
warn(
583+
`"compilerOptions" is only supported when using a build of Vue that ` +
584+
`includes the runtime compiler. Since you are using a runtime-only ` +
585+
`build, the options should be passed via your build tool config instead.`
586+
)
587+
}
581588
}
582589
// 0. create render proxy property access cache
583590
instance.accessCache = Object.create(null)
@@ -728,12 +735,19 @@ export function finishComponentSetup(
728735
startMeasure(instance, `compile`)
729736
}
730737
const { isCustomElement, compilerOptions } = instance.appContext.config
738+
const {
739+
delimiters,
740+
compilerOptions: componentCompilerOptions
741+
} = Component
731742
const finalCompilerOptions: CompilerOptions = extend(
732-
{
733-
isCustomElement: isCustomElement || NO,
734-
delimiters: Component.delimiters
735-
},
736-
compilerOptions
743+
extend(
744+
{
745+
isCustomElement,
746+
delimiters
747+
},
748+
compilerOptions
749+
),
750+
componentCompilerOptions
737751
)
738752
if (__COMPAT__) {
739753
// pass runtime compat config into the compiler

packages/runtime-core/src/componentOptions.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ export interface ComponentOptionsBase<
150150
expose?: string[]
151151
serverPrefetch?(): Promise<any>
152152

153+
// Runtime compiler only -----------------------------------------------------
154+
compilerOptions?: RuntimeCompilerOptions
155+
153156
// Internal ------------------------------------------------------------------
154157

155158
/**
@@ -203,6 +206,16 @@ export interface ComponentOptionsBase<
203206
__defaults?: Defaults
204207
}
205208

209+
/**
210+
* Subset of compiler options that makes sense for the runtime.
211+
*/
212+
export interface RuntimeCompilerOptions {
213+
isCustomElement?: (tag: string) => boolean
214+
whitespace?: 'preserve' | 'condense'
215+
comments?: boolean
216+
delimiters?: [string, string]
217+
}
218+
206219
export type ComponentOptionsWithoutProps<
207220
Props = {},
208221
RawBindings = {},
@@ -446,7 +459,10 @@ interface LegacyOptions<
446459
renderTriggered?: DebuggerHook
447460
errorCaptured?: ErrorCapturedHook
448461

449-
// runtime compile only
462+
/**
463+
* runtime compile only
464+
* @deprecated use `compilerOptions.delimiters` instead.
465+
*/
450466
delimiters?: [string, string]
451467

452468
/**

packages/runtime-core/src/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,8 @@ export {
179179
ComponentOptionsBase,
180180
RenderFunction,
181181
MethodOptions,
182-
ComputedOptions
182+
ComputedOptions,
183+
RuntimeCompilerOptions
183184
} from './componentOptions'
184185
export { EmitsOptions, ObjectEmitsOptions } from './componentEmits'
185186
export {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import { createApp } from 'vue'
2+
3+
describe('config.compilerOptions', () => {
4+
test('isCustomElement', () => {
5+
const app = createApp({
6+
template: `<foo/>`
7+
})
8+
app.config.compilerOptions.isCustomElement = (tag: string) => tag === 'foo'
9+
const root = document.createElement('div')
10+
app.mount(root)
11+
expect(root.innerHTML).toBe('<foo></foo>')
12+
})
13+
14+
test('comments', () => {
15+
const app = createApp({
16+
template: `<div/><!--test--><div/>`
17+
})
18+
app.config.compilerOptions.comments = true
19+
// the comments option is only relevant in production mode
20+
__DEV__ = false
21+
const root = document.createElement('div')
22+
app.mount(root)
23+
expect(root.innerHTML).toBe('<div></div><!--test--><div></div>')
24+
__DEV__ = true
25+
})
26+
27+
test('whitespace', () => {
28+
const app = createApp({
29+
template: `<div><span/>\n <span/></div>`
30+
})
31+
app.config.compilerOptions.whitespace = 'preserve'
32+
const root = document.createElement('div')
33+
app.mount(root)
34+
expect(root.firstChild!.childNodes.length).toBe(3)
35+
expect(root.firstChild!.childNodes[1].nodeType).toBe(Node.TEXT_NODE)
36+
})
37+
38+
test('delimiters', () => {
39+
const app = createApp({
40+
data: () => ({ foo: 'hi' }),
41+
template: `[[ foo ]]`
42+
})
43+
app.config.compilerOptions.delimiters = [`[[`, `]]`]
44+
const root = document.createElement('div')
45+
app.mount(root)
46+
expect(root.textContent).toBe('hi')
47+
})
48+
})
49+
50+
describe('per-component compilerOptions', () => {
51+
test('isCustomElement', () => {
52+
const app = createApp({
53+
template: `<foo/>`,
54+
compilerOptions: {
55+
isCustomElement: (tag: string) => tag === 'foo'
56+
}
57+
})
58+
const root = document.createElement('div')
59+
app.mount(root)
60+
expect(root.innerHTML).toBe('<foo></foo>')
61+
})
62+
63+
test('comments', () => {
64+
const app = createApp({
65+
template: `<div/><!--test--><div/>`,
66+
compilerOptions: {
67+
comments: true
68+
}
69+
})
70+
app.config.compilerOptions.comments = false
71+
// the comments option is only relevant in production mode
72+
__DEV__ = false
73+
const root = document.createElement('div')
74+
app.mount(root)
75+
expect(root.innerHTML).toBe('<div></div><!--test--><div></div>')
76+
__DEV__ = true
77+
})
78+
79+
test('whitespace', () => {
80+
const app = createApp({
81+
template: `<div><span/>\n <span/></div>`,
82+
compilerOptions: {
83+
whitespace: 'preserve'
84+
}
85+
})
86+
const root = document.createElement('div')
87+
app.mount(root)
88+
expect(root.firstChild!.childNodes.length).toBe(3)
89+
expect(root.firstChild!.childNodes[1].nodeType).toBe(Node.TEXT_NODE)
90+
})
91+
92+
test('delimiters', () => {
93+
const app = createApp({
94+
data: () => ({ foo: 'hi' }),
95+
template: `[[ foo ]]`,
96+
compilerOptions: {
97+
delimiters: [`[[`, `]]`]
98+
}
99+
})
100+
const root = document.createElement('div')
101+
app.mount(root)
102+
expect(root.textContent).toBe('hi')
103+
})
104+
})

0 commit comments

Comments
 (0)