Skip to content

Commit

Permalink
feat: support <script setup> in Vue 2.7 (supersedes #483) (#489)
Browse files Browse the repository at this point in the history
* feat: support <script setup> in Vue 2.7

* refactor: remove unnecessary bindingMetadata

* refactor: remove unnecessary refTransform

* feat: add setup to generateSourceMap

* chore: update Vue dependencies

* fix: remove inline sourceMap in vue2 setup scripts

* fix: update 2.x snapshot

* fix: use appropriate package according to vue version

* fix: rebase typo

* fix: make script setup & script blocks work together

* Update test.js.snap

* fixing snapshots

Co-authored-by: Felix Graf <git@felixgraf.dev>
Co-authored-by: Lachlan Miller <lachlan.miller.1990@outlook.com>
  • Loading branch information
3 people authored Sep 15, 2022
1 parent 1cd403d commit 7f2287c
Show file tree
Hide file tree
Showing 15 changed files with 216 additions and 60 deletions.
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
26 changes: 2 additions & 24 deletions e2e/2.x/basic/__snapshots__/test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`generates source maps for .vue files 1`] = `
{
"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",
"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": [
"name",
"computed",
Expand All @@ -21,29 +21,7 @@ exports[`generates source maps for .vue files 1`] = `
"Basic.vue",
],
"sourcesContent": [
"//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
"
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,
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')
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

0 comments on commit 7f2287c

Please sign in to comment.