diff --git a/plugins/plugin-vue/plugin-tsx-jsx.js b/plugins/plugin-vue/plugin-tsx-jsx.js new file mode 100644 index 0000000000..c2f32d021e --- /dev/null +++ b/plugins/plugin-vue/plugin-tsx-jsx.js @@ -0,0 +1,18 @@ +const fs = require('fs'); +const scriptCompilers = require('./src/script-compilers'); + +module.exports = function plugin(snowpackConfig, pluginOptions) { + return { + name: '@snowpack/plugin-vue-tsx-jsx', + resolve: { + input: ['.tsx', '.jsx'], + output: ['.js'], + }, + async load({filePath, fileExt}) { + const content = fs.readFileSync(filePath, 'utf-8'); + const lang = fileExt.slice(fileExt.lastIndexOf('.') + 1); + const result = scriptCompilers.esbuildCompile(content, lang); + return result; + }, + }; +}; diff --git a/plugins/plugin-vue/plugin.js b/plugins/plugin-vue/plugin.js index 6c8dc95236..40b9d2fd96 100644 --- a/plugins/plugin-vue/plugin.js +++ b/plugins/plugin-vue/plugin.js @@ -2,6 +2,7 @@ const fs = require('fs'); const path = require('path'); const hashsum = require('hash-sum'); const compiler = require('@vue/compiler-sfc'); +const scriptCompilers = require('./src/script-compilers'); /** Friendly error display */ function displayError({contents, filePath, error}) { @@ -56,14 +57,21 @@ module.exports = function plugin(snowpackConfig) { }; if (descriptor.script) { - output['.js'].code += descriptor.script.content.replace( - `export default`, - 'const defaultExport =', - ); + const scriptLang = descriptor.script.lang; + let scriptContent = descriptor.script.content; + if (['jsx', 'ts', 'tsx'].includes(scriptLang)) { + scriptContent = scriptCompilers.esbuildCompile( + scriptContent, + scriptLang, + ); + } + if (['js', 'ts'].includes(scriptLang) || !scriptLang) { + scriptContent = scriptContent.replace(`export default`, 'const defaultExport ='); + } + output['.js'].code += scriptContent; } else { output['.js'].code += `const defaultExport = {};`; } - await Promise.all( descriptor.styles.map((stylePart) => { const css = compiler.compileStyle({ diff --git a/plugins/plugin-vue/src/script-compilers.js b/plugins/plugin-vue/src/script-compilers.js new file mode 100644 index 0000000000..70a8021b0b --- /dev/null +++ b/plugins/plugin-vue/src/script-compilers.js @@ -0,0 +1,65 @@ +/* + +This license applies to parts of this file originating from the +https://github.com/vitejs/vite repository: + +MIT License + +Copyright (c) 2019-present, Yuxi (Evan) You + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +const esbuild = require('esbuild'); + +const codeSnippetH = `import { Fragment } from '/web_modules/vue.js';`; + +// https://github.com/vitejs/vite/blob/master/src/client/vueJsxCompat.ts +const codeSnippetVueJsxCompat = +`import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +}`; + +/** + * @param {string} content + * @param {'jsx' | 'ts' | 'tsx'} lang + */ +const esbuildCompile = (content, lang) => { + let result = ''; + if (['jsx', 'tsx'].includes(lang)) { + result += `${codeSnippetH}\n`; + result += `${codeSnippetVueJsxCompat}\n`; + } + const {js} = esbuild.transformSync(content, { + loader: lang, + jsxFactory: 'jsx', + jsxFragment: 'Fragment', + }); + result += `\n${js.trim()}\n`; + return result.trim(); +}; + +module.exports = { + esbuildCompile, +}; diff --git a/plugins/plugin-vue/test/__snapshots__/plugin-tsx-jsx.test.js.snap b/plugins/plugin-vue/test/__snapshots__/plugin-tsx-jsx.test.js.snap new file mode 100644 index 0000000000..4f68d3db2a --- /dev/null +++ b/plugins/plugin-vue/test/__snapshots__/plugin-tsx-jsx.test.js.snap @@ -0,0 +1,42 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`plugin with jsx 1`] = ` +"import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"JsxContent\\", + setup() { + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"JsxContent\\")); + } +});" +`; + +exports[`plugin with tsx 1`] = ` +"import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"TsxContent\\", + setup() { + const name = \\"TsxContent\\"; + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"TsxContent\\")); + } +});" +`; diff --git a/plugins/plugin-vue/test/__snapshots__/plugin-vue-ts-tsx-jsx.test.js.snap b/plugins/plugin-vue/test/__snapshots__/plugin-vue-ts-tsx-jsx.test.js.snap new file mode 100644 index 0000000000..7896791146 --- /dev/null +++ b/plugins/plugin-vue/test/__snapshots__/plugin-vue-ts-tsx-jsx.test.js.snap @@ -0,0 +1,87 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`plugin vue with jsx 1`] = ` +Object { + ".css": Object { + "code": "", + "map": "", + }, + ".js": Object { + "code": "import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"VueContentJsx\\", + setup() { + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"VueContentJsx\\")); + } +});", + "map": "", + }, +} +`; + +exports[`plugin vue with ts 1`] = ` +Object { + ".css": Object { + "code": "", + "map": "", + }, + ".js": Object { + "code": "import {defineComponent} from \\"vue\\"; +const defaultExport = defineComponent({ + name: \\"VueContentTs\\", + setup() { + const name = \\"VueContentTs\\"; + } +}); +import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from \\"/web_modules/vue.js\\" + +export function render(_ctx, _cache) { + return (_openBlock(), _createBlock(\\"h1\\", null, \\"Vue Content Ts\\")) +} + +defaultExport.render = render +export default defaultExport", + "map": "", + }, +} +`; + +exports[`plugin vue with tsx 1`] = ` +Object { + ".css": Object { + "code": "", + "map": "", + }, + ".js": Object { + "code": "import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"VueContentTsx\\", + setup() { + const name = \\"VueContentTsx\\"; + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"VueContentTsx\\")); + } +});", + "map": "", + }, +} +`; diff --git a/plugins/plugin-vue/test/__snapshots__/plugin.test.js.snap b/plugins/plugin-vue/test/__snapshots__/plugin.test.js.snap new file mode 100644 index 0000000000..16c50504ae --- /dev/null +++ b/plugins/plugin-vue/test/__snapshots__/plugin.test.js.snap @@ -0,0 +1,192 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`plugin base 1`] = ` +Object { + ".css": Object { + "code": " +.App { + text-align: center; +} +.App-header { + background-color: #f9f6f6; + color: #32485f; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} +.App-link { + color: #00c185; +} +.App-logo { + height: 40vmin; + pointer-events: none; + margin-bottom: 1rem; + animation: App-logo-spin infinite 1.6s ease-in-out alternate; +} +@keyframes App-logo-spin { +from { + transform: scale(1); +} +to { + transform: scale(1.06); +} +} +", + "map": "", + }, + ".js": Object { + "code": " +const defaultExport = { + data() { + return { + message: \\"Learn Vue\\" + }; + } +}; + +import { createVNode as _createVNode, createTextVNode as _createTextVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from \\"/web_modules/vue.js\\" + +const _hoisted_1 = { class: \\"App\\" } +const _hoisted_2 = { class: \\"App-header\\" } +const _hoisted_3 = /*#__PURE__*/_createVNode(\\"img\\", { + src: \\"/logo.svg\\", + class: \\"App-logo\\", + alt: \\"logo\\" +}, null, -1 /* HOISTED */) +const _hoisted_4 = /*#__PURE__*/_createVNode(\\"p\\", null, [ + /*#__PURE__*/_createTextVNode(\\" Edit \\"), + /*#__PURE__*/_createVNode(\\"code\\", null, \\"src/App.vue\\"), + /*#__PURE__*/_createTextVNode(\\" and save to reload. \\") +], -1 /* HOISTED */) +const _hoisted_5 = { + class: \\"App-link\\", + href: \\"https://vuejs.org\\", + target: \\"_blank\\", + rel: \\"noopener noreferrer\\" +} + +export function render(_ctx, _cache) { + return (_openBlock(), _createBlock(\\"div\\", _hoisted_1, [ + _createVNode(\\"header\\", _hoisted_2, [ + _hoisted_3, + _hoisted_4, + _createVNode(\\"a\\", _hoisted_5, _toDisplayString(_ctx.message), 1 /* TEXT */) + ]) + ])) +} + +defaultExport.render = render +export default defaultExport", + "map": "", + }, +} +`; + +exports[`plugin base only tpl 1`] = ` +Object { + ".css": Object { + "code": "", + "map": "", + }, + ".js": Object { + "code": "const defaultExport = {}; +import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from \\"/web_modules/vue.js\\" + +export function render(_ctx, _cache) { + return (_openBlock(), _createBlock(\\"h1\\", null, \\"Vue Content Only Tpl\\")) +} + +defaultExport.render = render +export default defaultExport", + "map": "", + }, +} +`; + +exports[`plugin base with sourceMap 1`] = ` +Object { + ".css": Object { + "code": " +.App { + text-align: center; +} +.App-header { + background-color: #f9f6f6; + color: #32485f; + min-height: 100vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-size: calc(10px + 2vmin); +} +.App-link { + color: #00c185; +} +.App-logo { + height: 40vmin; + pointer-events: none; + margin-bottom: 1rem; + animation: App-logo-spin infinite 1.6s ease-in-out alternate; +} +@keyframes App-logo-spin { +from { + transform: scale(1); +} +to { + transform: scale(1.06); +} +} +", + "map": "", + }, + ".js": Object { + "code": " +const defaultExport = { + data() { + return { + message: \\"Learn Vue\\" + }; + } +}; + +import { createVNode as _createVNode, createTextVNode as _createTextVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from \\"/web_modules/vue.js\\" + +const _hoisted_1 = { class: \\"App\\" } +const _hoisted_2 = { class: \\"App-header\\" } +const _hoisted_3 = /*#__PURE__*/_createVNode(\\"img\\", { + src: \\"/logo.svg\\", + class: \\"App-logo\\", + alt: \\"logo\\" +}, null, -1 /* HOISTED */) +const _hoisted_4 = /*#__PURE__*/_createVNode(\\"p\\", null, [ + /*#__PURE__*/_createTextVNode(\\" Edit \\"), + /*#__PURE__*/_createVNode(\\"code\\", null, \\"src/App.vue\\"), + /*#__PURE__*/_createTextVNode(\\" and save to reload. \\") +], -1 /* HOISTED */) +const _hoisted_5 = { + class: \\"App-link\\", + href: \\"https://vuejs.org\\", + target: \\"_blank\\", + rel: \\"noopener noreferrer\\" +} + +export function render(_ctx, _cache) { + return (_openBlock(), _createBlock(\\"div\\", _hoisted_1, [ + _createVNode(\\"header\\", _hoisted_2, [ + _hoisted_3, + _hoisted_4, + _createVNode(\\"a\\", _hoisted_5, _toDisplayString(_ctx.message), 1 /* TEXT */) + ]) + ])) +} + +defaultExport.render = render +export default defaultExport", + "map": "", + }, +} +`; diff --git a/plugins/plugin-vue/test/__snapshots__/script-compilers.test.js.snap b/plugins/plugin-vue/test/__snapshots__/script-compilers.test.js.snap new file mode 100644 index 0000000000..9375e0de31 --- /dev/null +++ b/plugins/plugin-vue/test/__snapshots__/script-compilers.test.js.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`esbuildCompile jsx 1`] = ` +"import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"JsxContent\\", + setup() { + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"JsxContent\\")); + } +});" +`; + +exports[`esbuildCompile ts 1`] = ` +"import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"TsContent\\", + setup() { + const name = \\"TsContent\\"; + } +});" +`; + +exports[`esbuildCompile tsx 1`] = ` +"import { Fragment } from '/web_modules/vue.js'; +import {createVNode, isVNode} from '/web_modules/vue.js'; +const slice = Array.prototype.slice; +export function jsx(tag, props = null, children = null) { + if (arguments.length > 3 || isVNode(children)) { + children = slice.call(arguments, 2); + } + return createVNode(tag, props, children); +} + +import {defineComponent} from \\"vue\\"; +export default defineComponent({ + name: \\"TsxContent\\", + setup() { + const name = \\"TsxContent\\"; + return () => /* @__PURE__ */ jsx(Fragment, null, /* @__PURE__ */ jsx(\\"h1\\", null, \\"TsxContent\\")); + } +});" +`; diff --git a/plugins/plugin-vue/test/plugin-tsx-jsx.test.js b/plugins/plugin-vue/test/plugin-tsx-jsx.test.js new file mode 100644 index 0000000000..2048a0930e --- /dev/null +++ b/plugins/plugin-vue/test/plugin-tsx-jsx.test.js @@ -0,0 +1,32 @@ +const path = require('path'); +const pluginTsxJsx = require('../plugin-tsx-jsx.js'); + +test('plugin with tsx', async () => { + const pluginInstance = pluginTsxJsx({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/TsxContent.tsx'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + fileExt: '.tsx', + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin with jsx', async () => { + const pluginInstance = pluginTsxJsx({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/JsxContent.jsx'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + fileExt: '.jsx', + }); + expect(resultContent).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/plugins/plugin-vue/test/plugin-vue-ts-tsx-jsx.test.js b/plugins/plugin-vue/test/plugin-vue-ts-tsx-jsx.test.js new file mode 100644 index 0000000000..ac20928d1b --- /dev/null +++ b/plugins/plugin-vue/test/plugin-vue-ts-tsx-jsx.test.js @@ -0,0 +1,44 @@ +const path = require('path'); +const plugin = require('../plugin'); + +test('plugin vue with ts', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContentTs.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin vue with tsx', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContentTsx.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin vue with jsx', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContentJsx.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/plugins/plugin-vue/test/plugin.test.js b/plugins/plugin-vue/test/plugin.test.js new file mode 100644 index 0000000000..98df2301c1 --- /dev/null +++ b/plugins/plugin-vue/test/plugin.test.js @@ -0,0 +1,58 @@ +const path = require('path'); +const plugin = require('../plugin'); + +test('plugin base', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: false, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContent.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin base with sourceMap', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContent.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin base only tpl', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContentOnlyTpl.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent).toMatchSnapshot(); +}); + +test('plugin base style scoped', async () => { + const pluginInstance = plugin({ + buildOptions: { + sourceMap: true, + }, + }); + const pluginLoad = pluginInstance.load; + const codeFilePath = path.resolve(__dirname, './stubs/VueContentStyleScoped.vue'); + const resultContent = await pluginLoad({ + filePath: codeFilePath, + }); + expect(resultContent['.css'].code).toMatch(/h1\[data-v-.*\]/) +}); \ No newline at end of file diff --git a/plugins/plugin-vue/test/script-compilers.test.js b/plugins/plugin-vue/test/script-compilers.test.js new file mode 100644 index 0000000000..0c23ca049f --- /dev/null +++ b/plugins/plugin-vue/test/script-compilers.test.js @@ -0,0 +1,24 @@ +const fs = require('fs'); +const path = require('path'); +const scriptCompilers = require('../src/script-compilers'); + +test('esbuildCompile ts', () => { + const { esbuildCompile } = scriptCompilers; + const codeContent = fs.readFileSync(path.resolve(__dirname, './stubs/TsContent.ts')).toString(); + const resultContent = esbuildCompile(codeContent, 'ts'); + expect(resultContent).toMatchSnapshot(); +}); + +test('esbuildCompile tsx', () => { + const { esbuildCompile } = scriptCompilers; + const codeContent = fs.readFileSync(path.resolve(__dirname, './stubs/TsxContent.tsx')).toString(); + const resultContent = esbuildCompile(codeContent, 'tsx'); + expect(resultContent).toMatchSnapshot(); +}); + +test('esbuildCompile jsx', () => { + const { esbuildCompile } = scriptCompilers; + const codeContent = fs.readFileSync(path.resolve(__dirname, './stubs/JsxContent.jsx')).toString(); + const resultContent = esbuildCompile(codeContent, 'jsx'); + expect(resultContent).toMatchSnapshot(); +}); \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/JsxContent.jsx b/plugins/plugin-vue/test/stubs/JsxContent.jsx new file mode 100644 index 0000000000..c35780d78c --- /dev/null +++ b/plugins/plugin-vue/test/stubs/JsxContent.jsx @@ -0,0 +1,12 @@ +import {defineComponent} from 'vue'; + +export default defineComponent({ + name: 'JsxContent', + setup() { + return () => ( + <> +

JsxContent

+ + ); + }, +}); diff --git a/plugins/plugin-vue/test/stubs/TsContent.ts b/plugins/plugin-vue/test/stubs/TsContent.ts new file mode 100644 index 0000000000..21162e7e77 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/TsContent.ts @@ -0,0 +1,8 @@ +import {defineComponent} from 'vue'; + +export default defineComponent({ + name: 'TsContent', + setup() { + const name: string = 'TsContent'; + }, +}); diff --git a/plugins/plugin-vue/test/stubs/TsxContent.tsx b/plugins/plugin-vue/test/stubs/TsxContent.tsx new file mode 100644 index 0000000000..5fd1826a2d --- /dev/null +++ b/plugins/plugin-vue/test/stubs/TsxContent.tsx @@ -0,0 +1,13 @@ +import {defineComponent} from 'vue'; + +export default defineComponent({ + name: 'TsxContent', + setup() { + const name: string = 'TsxContent'; + return () => ( + <> +

TsxContent

+ + ); + }, +}); diff --git a/plugins/plugin-vue/test/stubs/VueContent.vue b/plugins/plugin-vue/test/stubs/VueContent.vue new file mode 100644 index 0000000000..5134670b00 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContent.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/plugins/plugin-vue/test/stubs/VueContentJsx.vue b/plugins/plugin-vue/test/stubs/VueContentJsx.vue new file mode 100644 index 0000000000..375a38f291 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContentJsx.vue @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/VueContentOnlyTpl.vue b/plugins/plugin-vue/test/stubs/VueContentOnlyTpl.vue new file mode 100644 index 0000000000..a443d83225 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContentOnlyTpl.vue @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/VueContentStyleScoped.vue b/plugins/plugin-vue/test/stubs/VueContentStyleScoped.vue new file mode 100644 index 0000000000..802a70c90d --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContentStyleScoped.vue @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/VueContentTs.vue b/plugins/plugin-vue/test/stubs/VueContentTs.vue new file mode 100644 index 0000000000..0c46f9a3b1 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContentTs.vue @@ -0,0 +1,14 @@ + + + \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/VueContentTsx.vue b/plugins/plugin-vue/test/stubs/VueContentTsx.vue new file mode 100644 index 0000000000..8f2c03fdfa --- /dev/null +++ b/plugins/plugin-vue/test/stubs/VueContentTsx.vue @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/plugins/plugin-vue/test/stubs/tsconfig.json b/plugins/plugin-vue/test/stubs/tsconfig.json new file mode 100644 index 0000000000..2613afea43 --- /dev/null +++ b/plugins/plugin-vue/test/stubs/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "jsx": "preserve", + "jsxFactory": "h", + "jsxFragmentFactory": "Fragment" + } +} diff --git a/snowpack/src/commands/dev.ts b/snowpack/src/commands/dev.ts index ef9ef45780..0a899c1f58 100644 --- a/snowpack/src/commands/dev.ts +++ b/snowpack/src/commands/dev.ts @@ -644,6 +644,14 @@ If Snowpack is having trouble detecting the import, add ${colors.bold( const {code, map} = output[requestedFileExt]; let finalResponse = code; + // Wrap the response. + const hasAttachedCss = requestedFileExt === '.js' && !!output['.css']; + finalResponse = await wrapResponse(finalResponse, { + hasCssResource: hasAttachedCss, + sourceMap: map, + sourceMappingURL: path.basename(requestedFile.base) + '.map', + }); + // Resolve imports. if ( requestedFileExt === '.js' || @@ -657,14 +665,6 @@ If Snowpack is having trouble detecting the import, add ${colors.bold( ); } - // Wrap the response. - const hasAttachedCss = requestedFileExt === '.js' && !!output['.css']; - finalResponse = await wrapResponse(finalResponse, { - hasCssResource: hasAttachedCss, - sourceMap: map, - sourceMappingURL: path.basename(requestedFile.base) + '.map', - }); - // Return the finalized response. return finalResponse; }