-
Notifications
You must be signed in to change notification settings - Fork 156
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support <script setup> in Vue 2.7 (supersedes #483) #489
Changes from all commits
4a44afc
25fd721
571831a
98bf7ce
26b9cf1
cb740dc
bcbfcb4
25c67a0
189f226
632622b
8126d93
4e93580
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
<template> | ||
<div> | ||
<button @click="increase">Count: {{ num }}</button> | ||
<Basic /> | ||
<span>{{ msg }}</span> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { ref } from 'vue' | ||
import Basic from './Basic.vue' | ||
|
||
const num = ref(5) | ||
const greet = () => console.log('greet') | ||
const increase = () => { | ||
greet() | ||
num.value++ | ||
} | ||
const msg = 'hello world' | ||
</script> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
const { SourceMapGenerator, SourceMapConsumer } = require('source-map') | ||
|
||
// based on @vue/compiler-sfc mapLines | ||
module.exports = function mapLines(oldMap, newMap) { | ||
if (!oldMap) return newMap | ||
if (!newMap) return oldMap | ||
|
||
const oldMapConsumer = new SourceMapConsumer(oldMap) | ||
const newMapConsumer = new SourceMapConsumer(newMap) | ||
const mergedMapGenerator = new SourceMapGenerator() | ||
|
||
newMapConsumer.eachMapping(m => { | ||
if (m.originalLine == null) { | ||
return | ||
} | ||
|
||
const origPosInOldMap = oldMapConsumer.originalPositionFor({ | ||
line: m.originalLine, | ||
column: m.originalColumn | ||
}) | ||
|
||
if (origPosInOldMap.source == null) { | ||
return | ||
} | ||
|
||
mergedMapGenerator.addMapping({ | ||
generated: { | ||
line: m.generatedLine, | ||
column: m.generatedColumn | ||
}, | ||
original: { | ||
line: origPosInOldMap.line, // map line | ||
// use current column, since the oldMap produced by @vue/compiler-sfc | ||
// does not | ||
column: m.originalColumn | ||
}, | ||
source: origPosInOldMap.source, | ||
name: origPosInOldMap.name | ||
}) | ||
}) | ||
|
||
// source-map's type definition is incomplete | ||
const generator = mergedMapGenerator | ||
oldMapConsumer.sources.forEach(sourceFile => { | ||
generator._sources.add(sourceFile) | ||
const sourceContent = oldMapConsumer.sourceContentFor(sourceFile) | ||
if (sourceContent != null) { | ||
mergedMapGenerator.setSourceContent(sourceFile, sourceContent) | ||
} | ||
}) | ||
|
||
generator._sourceRoot = oldMap.sourceRoot | ||
generator._file = oldMap.file | ||
return generator.toJSON() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,8 +8,19 @@ const stripInlineSourceMap = require('./utils').stripInlineSourceMap | |
const getCustomTransformer = require('./utils').getCustomTransformer | ||
const loadSrc = require('./utils').loadSrc | ||
const babelTransformer = require('babel-jest').default | ||
const compilerUtils = require('@vue/component-compiler-utils') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thebanjomatic this import used to be here anyway, without being declared explicitly in the peer dependencies. My exposure to this codebase is limited so I am not really aware of the consequences of these changes given the amount of permutations we can have in regards of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The thing is that its already a peer dependency, the project just isn't declaring it in the package.json manifest. This would have issues if you were using yarn pnp for example because it is trying to import a package that isn't declared and you would need to use packageExtensions to inject those declarations as consumers of the library. If you don't want to make the change in this PR, that's fine. I might pursue a separate PR later to clean up these undeclared peerDependencies and to fully optionalize vue-template-compiler so that you don't need to install that separately for vue 2.7 also. I do think There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @thebanjomatic that’s a fair point. I can change this PR. Will update it later. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LMK when it's ready for a re-review. Providing compat for all versions is really hard and tedious... :| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PS just released v29 for Jest 29 You might need to rebase. If this merges, the changes will be in v29 - we can back port to v28, but it's a lot of work to maintain multiple versions, I generally ask people to update to the latest Jest. https://github.com/vuejs/vue-jest/releases/tag/v29.0.0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @lmiller1990 sorry I’ve been kinda busy last week, so what’s your recommendation? Make this change only compatible with Jest 29? |
||
const generateCode = require('./generate-code') | ||
const mapLines = require('./map-lines') | ||
const vueComponentNamespace = require('./constants').vueComponentNamespace | ||
|
||
let isVue27 = false | ||
let compilerUtils | ||
|
||
try { | ||
compilerUtils = require('vue/compiler-sfc') | ||
isVue27 = true | ||
} catch (e) { | ||
compilerUtils = require('@vue/component-compiler-utils') | ||
} | ||
|
||
function resolveTransformer(lang = 'js', vueJestConfig) { | ||
const transformer = getCustomTransformer(vueJestConfig['transform'], lang) | ||
|
@@ -42,7 +53,33 @@ function processScript(scriptPart, filePath, config) { | |
return result | ||
} | ||
|
||
function processTemplate(template, filename, config) { | ||
function processScriptSetup(descriptor, filePath, config) { | ||
if (!descriptor.scriptSetup) { | ||
return null | ||
} | ||
const vueJestConfig = getVueJestConfig(config) | ||
const content = compilerUtils.compileScript(descriptor, { | ||
id: filePath, | ||
reactivityTransform: true, | ||
...vueJestConfig.compilerOptions | ||
}) | ||
const contentMap = mapLines(descriptor.scriptSetup.map, content.map) | ||
|
||
const transformer = resolveTransformer( | ||
descriptor.scriptSetup.lang, | ||
vueJestConfig | ||
) | ||
|
||
const result = transformer.process(content.content, filePath, config) | ||
result.code = stripInlineSourceMap(result.code) | ||
result.map = mapLines(contentMap, result.map) | ||
|
||
return result | ||
} | ||
|
||
function processTemplate(descriptor, filename, config) { | ||
const { template, scriptSetup } = descriptor | ||
|
||
if (!template) { | ||
return null | ||
} | ||
|
@@ -53,6 +90,16 @@ function processTemplate(template, filename, config) { | |
template.content = loadSrc(template.src, filename) | ||
} | ||
|
||
let bindings | ||
if (isVue27 && scriptSetup) { | ||
const scriptSetupResult = compilerUtils.compileScript(descriptor, { | ||
id: filename, | ||
reactivityTransform: true, | ||
...vueJestConfig.compilerOptions | ||
}) | ||
bindings = scriptSetupResult.bindings | ||
} | ||
|
||
const userTemplateCompilerOptions = vueJestConfig.templateCompiler || {} | ||
const result = compilerUtils.compileTemplate({ | ||
source: template.content, | ||
|
@@ -63,9 +110,10 @@ function processTemplate(template, filename, config) { | |
preprocessOptions: vueJestConfig[template.lang], | ||
...userTemplateCompilerOptions, | ||
compilerOptions: { | ||
optimize: false, | ||
...(!isVue27 ? { optimize: false } : {}), | ||
...userTemplateCompilerOptions.compilerOptions | ||
} | ||
}, | ||
...(isVue27 ? { bindings } : {}) | ||
}) | ||
|
||
logResultErrors(result) | ||
|
@@ -91,16 +139,21 @@ function processStyle(styles, filename, config) { | |
module.exports = function(src, filename, config) { | ||
const descriptor = compilerUtils.parse({ | ||
source: src, | ||
compiler: VueTemplateCompiler, | ||
compiler: isVue27 ? undefined : VueTemplateCompiler, | ||
filename | ||
}) | ||
|
||
const templateResult = processTemplate(descriptor.template, filename, config) | ||
const componentNamespace = | ||
getVueJestConfig(config)['componentNamespace'] || vueComponentNamespace | ||
|
||
const templateResult = processTemplate(descriptor, filename, config) | ||
const scriptResult = processScript(descriptor.script, filename, config) | ||
const scriptSetupResult = processScriptSetup(descriptor, filename, config) | ||
const stylesResult = processStyle(descriptor.styles, filename, config) | ||
const customBlocksResult = processCustomBlocks( | ||
descriptor.customBlocks, | ||
filename, | ||
componentNamespace, | ||
config | ||
) | ||
|
||
|
@@ -114,6 +167,7 @@ module.exports = function(src, filename, config) { | |
|
||
const output = generateCode( | ||
scriptResult, | ||
scriptSetupResult, | ||
templateResult, | ||
stylesResult, | ||
customBlocksResult, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a breaking change (bug?) introduced for custom block processors. This import in
process.js
is just undefined, because./constants
does not havevueComponentNamespace
:This means that the
vueOptionsNamespace
in the custom processor will always be undefined. This currently breaks vue-i18n-jest for me here:https://github.com/intlify/vue-i18n-jest/blob/afaa5c3d4dd2e54760a5ef73cd2829672348cf25/src/process.ts#L43
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Argh, sorry. Can you file an issue with a minimal repro?
Bonus points if you want to make a PR!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Edit: you already made a PR!