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

fix: update the .vue file shim for Vue 3 #5903

Merged
merged 4 commits into from Sep 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/@vue/cli-plugin-babel/package.json
Expand Up @@ -32,7 +32,7 @@
"@vue/cli-service": "^3.0.0 || ^4.0.0-0"
},
"devDependencies": {
"jscodeshift": "^0.9.0"
"jscodeshift": "^0.10.0"
},
"publishConfig": {
"access": "public"
Expand Down
@@ -0,0 +1,5 @@
declare module '*.vue' {
import { defineComponent } from 'vue';
const component: ReturnType<typeof defineComponent>;
export default component;
}
@@ -0,0 +1,5 @@
declare module '*.vue' {
import { DefineComponent } from 'vue';
const component: DefineComponent;
export default component;
}
@@ -0,0 +1,5 @@
jest.autoMockOff()

const { defineTest } = require('jscodeshift/dist/testUtils')

defineTest(__dirname, 'migrateComponentType', null, 'shims-vue', { parser: 'ts' })
@@ -0,0 +1,93 @@
// `shims-vue.d.ts` for Vue 3, generated by CLI 4.5.0-4.5.6, uses the following declaration:
// `component: ReturnType<typeof defineComponent>`

// So needs to update to:
// `component: DefineComponent`

module.exports = function migrateComponentType (file, api) {
const j = api.jscodeshift
const root = j(file.source)

const useDoubleQuote = root.find(j.StringLiteral).some(({ node }) => node.extra.raw.startsWith('"'))

const tsmodule = root.find(j.TSModuleDeclaration, {
id: {
value: '*.vue'
}
})

const componentDecl = tsmodule.find(j.VariableDeclarator, {
id: {
name: 'component',
typeAnnotation: {
typeAnnotation: {
typeName: {
name: 'ReturnType'
},
typeParameters: {
params: {
0: {
exprName: {
name: 'defineComponent'
}
}
}
}
}
}
}
})

if (componentDecl.length !== 1) {
return file.source
}

// update the component type
componentDecl.forEach(({ node }) => {
node.id.typeAnnotation = j.tsTypeAnnotation(
j.tsTypeReference(j.identifier('DefineComponent'))
)
})

// insert DefineComponent type import
const importDeclFromVue = tsmodule.find(j.ImportDeclaration, {
source: {
value: 'vue'
}
})
importDeclFromVue
.get(0)
.node.specifiers.push(j.importSpecifier(j.identifier('DefineComponent')))

// remove defineComponent import if unused
const defineComponentUsages = tsmodule
.find(j.Identifier, { name: 'defineComponent' })
.filter((identifierPath) => {
const parent = identifierPath.parent.node

// Ignore the import specifier
if (
j.ImportDefaultSpecifier.check(parent) ||
j.ImportSpecifier.check(parent) ||
j.ImportNamespaceSpecifier.check(parent)
) {
return false
}
})
if (defineComponentUsages.length === 0) {
tsmodule
.find(j.ImportSpecifier, {
local: {
name: 'defineComponent'
}
})
.remove()
}

return root.toSource({
lineTerminator: '\n',
quote: useDoubleQuote ? 'double' : 'single'
})
}

module.exports.parser = 'ts'
@@ -1,5 +1,5 @@
declare module '*.vue' {
import { defineComponent } from 'vue'
const component: ReturnType<typeof defineComponent>
import type { DefineComponent } from 'vue'
const component: DefineComponent
Comment on lines +2 to +3
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pikax @cexbrayat
Just to make sure I get it right.
Is this the recommended way to shim .vue files now in Vue 3 stable?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you have something weird with import type, but otherwise yes this is what I've been using:

declare module '*.vue' {
  import { DefineComponent } from 'vue';
  const component: DefineComponent;
  export default component;
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does "something weird with import type" mean?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if I wasn't clear: I don't think import type is necessary here, as DefineComponent is just a type, so there is no tree-shaking issue. I'm fine if you prefer to keep it, I was just pointing out that the syntax is a bit more advanced, and might lose some developers not familiar with the latest TS features

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Now that it's only a style issue then I'll keep it. Because now Vue CLI scaffolds with TS 3.9+, which supports this syntax. And the import type syntax is quite self-explaining so that people won't mistakenly take DefineComponent as a value, making the code a little clearer.

export default component
}
7 changes: 6 additions & 1 deletion packages/@vue/cli-plugin-typescript/migrator/index.js
@@ -1,4 +1,4 @@
module.exports = api => {
module.exports = (api, options, rootOptions) => {
api.extendPackage(
{
devDependencies: {
Expand All @@ -7,4 +7,9 @@ module.exports = api => {
},
{ warnIncompatibleVersions: false }
)

// update vue 3 typescript shim
if (rootOptions.vueVersion === 3) {
api.transformScript('src/shims-vue.d.ts', require('../codemods/migrateComponentType'))
}
}
1 change: 1 addition & 0 deletions packages/@vue/cli-plugin-typescript/package.json
Expand Up @@ -51,6 +51,7 @@
"@types/chai": "^4.2.11",
"@types/jest": "^24.0.19",
"@types/mocha": "^5.2.6",
"jscodeshift": "^0.10.0",
"typescript": "~3.9.3",
"vue-class-component": "^7.2.3",
"vue-property-decorator": "^8.4.2"
Expand Down
2 changes: 1 addition & 1 deletion packages/@vue/cli-service/__tests__/generator.spec.js
Expand Up @@ -42,7 +42,7 @@ test('Vue 3', async () => {
vueVersion: '3'
})

expect(pkg.dependencies.vue).toBe('^3.0.0-0')
expect(pkg.dependencies.vue).toBe('^3.0.0')
expect(pkg).toHaveProperty(['devDependencies', '@vue/compiler-sfc'])

expect(files['src/main.js']).toMatch(`import { createApp } from 'vue'`)
Expand Down
4 changes: 2 additions & 2 deletions packages/@vue/cli-service/generator/index.js
Expand Up @@ -6,10 +6,10 @@ module.exports = (api, options) => {
if (options.vueVersion === '3') {
api.extendPackage({
dependencies: {
'vue': '^3.0.0-0'
'vue': '^3.0.0'
},
devDependencies: {
'@vue/compiler-sfc': '^3.0.0-0'
'@vue/compiler-sfc': '^3.0.0'
}
})
} else {
Expand Down
25 changes: 0 additions & 25 deletions yarn.lock
Expand Up @@ -12518,31 +12518,6 @@ jscodeshift@^0.10.0:
temp "^0.8.1"
write-file-atomic "^2.3.0"

jscodeshift@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/jscodeshift/-/jscodeshift-0.9.0.tgz#672025658e868a63e24d6a6f4c44af9edb6e55f3"
integrity sha512-SUeXq8dJzj5LR8uy71axgG3bmiHoC0IdHy7n89SqKzkzBWpAds5F9IIGE+lqUSZX9J0ZfEzN8fXWIqQV0dIp2w==
dependencies:
"@babel/core" "^7.1.6"
"@babel/parser" "^7.1.6"
"@babel/plugin-proposal-class-properties" "^7.1.0"
"@babel/plugin-proposal-nullish-coalescing-operator" "^7.1.0"
"@babel/plugin-proposal-optional-chaining" "^7.1.0"
"@babel/plugin-transform-modules-commonjs" "^7.1.0"
"@babel/preset-flow" "^7.0.0"
"@babel/preset-typescript" "^7.1.0"
"@babel/register" "^7.0.0"
babel-core "^7.0.0-bridge.0"
colors "^1.1.2"
flow-parser "0.*"
graceful-fs "^4.1.11"
micromatch "^3.1.10"
neo-async "^2.5.0"
node-dir "^0.1.17"
recast "^0.18.1"
temp "^0.8.1"
write-file-atomic "^2.3.0"

jsdom-global@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9"
Expand Down