Skip to content
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

Merged
merged 12 commits into from
Sep 15, 2022
4 changes: 2 additions & 2 deletions e2e/2.x/babel-in-package/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
},
"dependencies": {
"source-map": "0.5.6",
"vue": "^2.5.21",
"vue-template-compiler": "^2.5.21"
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7"
},
"devDependencies": {
"@babel/core": "^7.9.0",
Expand Down
32 changes: 5 additions & 27 deletions e2e/2.x/basic/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`generates source maps for .vue files 1`] = `
{
Object {
"file": "./components/Basic.vue",
"mappings": ";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;eAEe;AACbA,MAAI,EAAE,OADO;AAEbC,UAAQ,EAAE;AACRC,kBAAc,EAAE,SAASA,cAAT,GAA0B;AACxC,aAAO;AACLC,WAAG,EAAE,KAAKC,OADL;AAELC,YAAI,EAAE,CAAC,KAAKD,OAFP;AAGLE,cAAM,EAAE,KAAKF;AAHR,OAAP;AAKD;AAPO,GAFG;AAWbG,MAAI,EAAE,SAASA,IAAT,GAAgB;AACpB,WAAO;AACLC,SAAG,EAAE,4BADA;AAELJ,aAAO,EAAE;AAFJ,KAAP;AAID,GAhBY;AAiBbK,SAAO,EAAE;AACPC,eAAW,EAAE,SAASA,WAAT,GAAuB;AAClC,WAAKN,OAAL,GAAe,CAAC,KAAKA,OAArB;AACD;AAHM;AAjBI,C",
"names": [
"mappings": ";;;;;;eACe;AACbA,MAAI,EAAE,OADO;AAEbC,UAAQ,EAAE;AACRC,kBAAc,EAAE,SAASA,cAAT,GAA0B;AACxC,aAAO;AACLC,WAAG,EAAE,KAAKC,OADL;AAELC,YAAI,EAAE,CAAC,KAAKD,OAFP;AAGLE,cAAM,EAAE,KAAKF;AAHR,OAAP;AAKD;AAPO,GAFG;AAWbG,MAAI,EAAE,SAASA,IAAT,GAAgB;AACpB,WAAO;AACLC,SAAG,EAAE,4BADA;AAELJ,aAAO,EAAE;AAFJ,KAAP;AAID,GAhBY;AAiBbK,SAAO,EAAE;AACPC,eAAW,EAAE,SAASA,WAAT,GAAuB;AAClC,WAAKN,OAAL,GAAe,CAAC,KAAKA,OAArB;AACD;AAHM;AAjBI,C",
"names": Array [
"name",
"computed",
"headingClasses",
Expand All @@ -20,30 +20,8 @@ exports[`generates source maps for .vue files 1`] = `
"sources": [
"Basic.vue",
],
"sourcesContent": [
"//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//

"sourcesContent": Array [
"
export default {
name: 'basic',
computed: {
Expand Down
20 changes: 20 additions & 0 deletions e2e/2.x/basic/components/ScriptSetup.vue
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>
4 changes: 2 additions & 2 deletions e2e/2.x/basic/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"test": "jest --no-cache --coverage test.js"
},
"dependencies": {
"vue": "^2.5.21",
"vue-template-compiler": "^2.5.21"
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7"
},
"devDependencies": {
"@babel/core": "^7.9.0",
Expand Down
7 changes: 7 additions & 0 deletions e2e/2.x/basic/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import PugRelative from './components/PugRelativeExtends.vue'
import Jsx from './components/Jsx.vue'
import Constructor from './components/Constructor.vue'
import { compileStyle } from '@vue/component-compiler-utils'
import ScriptSetup from './components/ScriptSetup'
jest.mock('@vue/component-compiler-utils', () => ({
...jest.requireActual('@vue/component-compiler-utils'),
compileStyle: jest.fn(() => ({ errors: [], code: '' }))
Expand Down Expand Up @@ -156,6 +157,12 @@ test('processes SFC with no template', () => {
expect(wrapper.element.tagName).toBe('SECTION')
})

test('processes SFC with <script setup>', () => {
const wrapper = mount(ScriptSetup)
expect(wrapper.html()).toContain('Count: 5')
expect(wrapper.html()).toContain('Welcome to Your Vue.js App')
})

test('should pass properly "styleOptions" into "preprocessOptions"', () => {
const filePath = resolve(__dirname, './components/Basic.vue')
const fileString = readFileSync(filePath, { encoding: 'utf8' })
Expand Down
4 changes: 2 additions & 2 deletions e2e/2.x/custom-transformers/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"test": "jest --no-cache --coverage test.js"
},
"dependencies": {
"vue": "^2.5.21",
"vue-template-compiler": "^2.5.21"
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7"
},
"devDependencies": {
"@babel/core": "^7.9.0",
Expand Down
4 changes: 2 additions & 2 deletions e2e/2.x/sass-importer/entry/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"test": "jest --no-cache --coverage test.js"
},
"dependencies": {
"vue": "^2.5.21",
"vue-template-compiler": "^2.5.21",
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7",
"vue2-sass-importer-lib": "file:../lib",
"vue2-sass-importer-sass-lib": "file:../sass-lib-v2"
},
Expand Down
2 changes: 1 addition & 1 deletion e2e/2.x/sass-importer/lib/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
"vue2-sass-importer-sass-lib": "file:../sass-lib-v1"
},
"peerDependencies": {
"vue": "^2.5.21"
"vue": "^2.7.7"
}
}
4 changes: 2 additions & 2 deletions e2e/2.x/style/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
"test": "node setup.js && jest --no-cache test.js"
},
"dependencies": {
"vue": "^2.5.21",
"vue-template-compiler": "^2.5.21"
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7"
},
"devDependencies": {
"@babel/core": "^7.9.0",
Expand Down
6 changes: 4 additions & 2 deletions packages/vue2-jest/lib/generate-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function addToSourceMap(node, result) {

module.exports = function generateCode(
scriptResult,
scriptSetupResult,
templateResult,
stylesResult,
customBlocksResult,
Expand All @@ -26,8 +27,9 @@ module.exports = function generateCode(
) {
var node = new SourceNode(null, null)

if (scriptResult) {
addToSourceMap(node, scriptResult)
if (scriptResult || scriptSetupResult) {
scriptResult && addToSourceMap(node, scriptResult)
scriptSetupResult && addToSourceMap(node, scriptSetupResult)
} else {
node.add(
`Object.defineProperty(exports, "__esModule", {\n` +
Expand Down
55 changes: 55 additions & 0 deletions packages/vue2-jest/lib/map-lines.js
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()
}
5 changes: 2 additions & 3 deletions packages/vue2-jest/lib/process-custom-blocks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const { getVueJestConfig, getCustomTransformer } = require('./utils')
const vueOptionsNamespace = require('./constants').vueOptionsNamespace

function applyTransformer(
transformer,
Expand All @@ -17,7 +16,7 @@ function groupByType(acc, block) {
return acc
}

module.exports = function(allBlocks, filename, config) {
module.exports = function(allBlocks, filename, componentNamespace, config) {
const blocksByType = allBlocks.reduce(groupByType, {})
const code = []
for (const [type, blocks] of Object.entries(blocksByType)) {
Expand All @@ -29,7 +28,7 @@ module.exports = function(allBlocks, filename, config) {
const codeStr = applyTransformer(
transformer,
blocks,
vueOptionsNamespace,
componentNamespace,
Copy link
Contributor

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 have vueComponentNamespace:

const vueComponentNamespace = require('./constants').vueComponentNamespace

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

Copy link
Member

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!!

Copy link
Member

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!

filename,
config
)
Expand Down
66 changes: 60 additions & 6 deletions packages/vue2-jest/lib/process.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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 vue-jest,jest, and vue versions.

Copy link
Contributor

Choose a reason for hiding this comment

The 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 vue/compiler-sfc is still the better import than @vue/compiler-sfc though since we already have the vue peer dependency declared and this appears to be the preferred way to import compiler-sfc now that it ships with the vue dependency out of the box.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The 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... :|

Copy link
Member

Choose a reason for hiding this comment

The 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

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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)
Expand Down Expand Up @@ -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
}
Expand All @@ -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,
Expand All @@ -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)
Expand All @@ -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
)

Expand All @@ -114,6 +167,7 @@ module.exports = function(src, filename, config) {

const output = generateCode(
scriptResult,
scriptSetupResult,
templateResult,
stylesResult,
customBlocksResult,
Expand Down
4 changes: 2 additions & 2 deletions packages/vue2-jest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
"jest": "29.x",
"semantic-release": "^15.13.2",
"typescript": "^4.6.4",
"vue": "^2.4.2",
"vue-template-compiler": "^2.4.2"
"vue": "^2.7.7",
"vue-template-compiler": "^2.7.7"
},
"peerDependencies": {
"@babel/core": "7.x",
Expand Down
Loading