diff --git a/packages/core/integration-tests/test/integration/vue-ts-template/App.vue b/packages/core/integration-tests/test/integration/vue-ts-template/App.vue
new file mode 100644
index 00000000000..859cda55e0e
--- /dev/null
+++ b/packages/core/integration-tests/test/integration/vue-ts-template/App.vue
@@ -0,0 +1,7 @@
+
+
+
+ {{ (x as number).toFixed(2) }}
+
diff --git a/packages/core/integration-tests/test/vue.js b/packages/core/integration-tests/test/vue.js
index 03096229731..0cfcd4b192e 100644
--- a/packages/core/integration-tests/test/vue.js
+++ b/packages/core/integration-tests/test/vue.js
@@ -113,4 +113,12 @@ describe('vue', function () {
assert.equal(typeof output.render, 'function');
assert.equal(typeof output.setup, 'function');
});
+ it('should process template with TS when script is TS', async function () {
+ let b = await bundle(
+ path.join(__dirname, '/integration/vue-ts-template/App.vue'),
+ );
+ let output = (await run(b)).default;
+ assert.equal(typeof output.render, 'function');
+ assert.equal(typeof output.setup, 'function');
+ });
});
diff --git a/packages/transformers/vue/src/VueTransformer.js b/packages/transformers/vue/src/VueTransformer.js
index 4d5bf8f2aef..968ede917c6 100644
--- a/packages/transformers/vue/src/VueTransformer.js
+++ b/packages/transformers/vue/src/VueTransformer.js
@@ -199,6 +199,47 @@ function createDiagnostic(err, filePath) {
return diagnostic;
}
+function getScriptType(script) {
+ if (!script) {
+ return 'js';
+ }
+
+ if (script.src) {
+ script.lang = extname(script.src).slice(1);
+ }
+ let type;
+ switch (script.lang || 'js') {
+ case 'javascript':
+ case 'js':
+ type = 'js';
+ break;
+ case 'jsx':
+ type = 'jsx';
+ break;
+ case 'typescript':
+ case 'ts':
+ type = 'ts';
+ break;
+ case 'tsx':
+ type = 'tsx';
+ break;
+ case 'coffeescript':
+ case 'coffee':
+ type = 'coffee';
+ break;
+ default:
+ // TODO: codeframe
+ throw new ThrowableDiagnostic({
+ diagnostic: {
+ message: md`Unknown script language: "${script.lang}"`,
+ origin: '@parcel/transformer-vue',
+ },
+ });
+ }
+
+ return type;
+}
+
async function processPipeline({
asset,
template,
@@ -244,6 +285,14 @@ async function processPipeline({
}
content = await preprocessor.render(content, options);
}
+
+ // if using TS, support TS syntax in template expressions
+ const expressionPlugins = config.compilerOptions?.expressionPlugins || [];
+ const type = getScriptType(script);
+ if (type === 'ts') {
+ expressionPlugins.push('typescript');
+ }
+
let templateComp = compiler.compileTemplate({
filename: asset.filePath,
source: content,
@@ -253,6 +302,7 @@ async function processPipeline({
compilerOptions: {
...config.compilerOptions,
bindingMetadata: script ? script.bindings : undefined,
+ expressionPlugins,
},
isProd: options.mode === 'production',
id,
@@ -265,7 +315,7 @@ async function processPipeline({
});
}
let templateAsset: TransformerResult = {
- type: 'js',
+ type,
uniqueKey: asset.id + '-template',
...(!template.src &&
asset.env.sourceMap && {
@@ -295,35 +345,7 @@ ${
).toString();
script.lang = extname(script.src).slice(1);
}
- let type;
- switch (script.lang || 'js') {
- case 'javascript':
- case 'js':
- type = 'js';
- break;
- case 'jsx':
- type = 'jsx';
- break;
- case 'typescript':
- case 'ts':
- type = 'ts';
- break;
- case 'tsx':
- type = 'tsx';
- break;
- case 'coffeescript':
- case 'coffee':
- type = 'coffee';
- break;
- default:
- // TODO: codeframe
- throw new ThrowableDiagnostic({
- diagnostic: {
- message: md`Unknown script language: "${script.lang}"`,
- origin: '@parcel/transformer-vue',
- },
- });
- }
+ let type = getScriptType(script);
let scriptAsset = {
type,
uniqueKey: asset.id + '-script',