From 85c2b1bb0453deab10bbe55199a7956509e6e6d7 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Tue, 29 Jun 2021 02:49:35 +0300 Subject: [PATCH] feat: add @vue/compat initial support (#698) * feat: add @vue/compat initial support * chore: better way to detect legacy components --- .github/workflows/ci.yml | 2 ++ jest.config.js | 4 +++- package.json | 7 ++++-- src/stubs.ts | 7 +++++- src/utils/find.ts | 5 +++- src/utils/vueCompatSupport.ts | 21 +++++++++++++++++ tests-compat/compat.spec.ts | 38 ++++++++++++++++++++++++++++++ tests-compat/jest-compat.config.js | 8 +++++++ types/compat.ts | 3 +++ yarn.lock | 5 ++++ 10 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 src/utils/vueCompatSupport.ts create mode 100644 tests-compat/compat.spec.ts create mode 100644 tests-compat/jest-compat.config.js create mode 100644 types/compat.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf7c381d8..6458a7d73 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,9 +27,11 @@ jobs: - run: yarn install - run: yarn lint - run: yarn test + - run: yarn test:compat - run: yarn build env: CI: true - run: yarn test:build + - run: yarn test:compat:build - run: yarn tsd - run: yarn vue-tsc diff --git a/jest.config.js b/jest.config.js index 49ace6603..0fe7260da 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,3 +1,5 @@ +const path = require('path') + module.exports = { preset: 'ts-jest', globals: { @@ -14,5 +16,5 @@ module.exports = { '^.+\\js$': 'babel-jest' }, moduleFileExtensions: ['vue', 'js', 'json', 'jsx', 'ts', 'tsx', 'node'], - setupFiles: ['./setup.js'] + setupFiles: [path.resolve(__dirname, './setup.js')] } diff --git a/package.json b/package.json index 755127264..46186be94 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@types/node": "15.12.4", "@types/pretty": "^2.0.0", "@vue/babel-plugin-jsx": "^1.0.6", + "@vue/compat": "^3.1.2", "@vue/compiler-dom": "^3.1.2", "@vue/compiler-sfc": "3.1.2", "babel-jest": "^26.6.3", @@ -55,8 +56,10 @@ "email": "lachlan.miller.1990@outlook.com" }, "scripts": { - "test": "yarn jest --runInBand tests", - "test:build": "yarn jest --runInBand tests -use-build", + "test": "yarn jest --runInBand tests/", + "test:compat": "yarn jest -c tests-compat/jest-compat.config.js --runInBand tests-compat/", + "test:build": "yarn jest --runInBand tests/ -use-build", + "test:compat:build": "yarn jest -c tests-compat/jest-compat.config.js --runInBand tests-compat/ -use-build", "tsd": "tsc -p test-dts/tsconfig.tsd.json", "build": "yarn rollup -c rollup.config.js", "lint": "prettier -c --parser typescript \"(src|tests)/**/*.ts?(x)\"", diff --git a/src/stubs.ts b/src/stubs.ts index 34f166279..30e79f785 100644 --- a/src/stubs.ts +++ b/src/stubs.ts @@ -61,7 +61,12 @@ const createTransitionStub = ({ return h(name, {}, ctx.$slots) } - return defineComponent({ name, render, props }) + return defineComponent({ + name, + compatConfig: { MODE: 3, RENDER_FUNCTION: false }, + render, + props + }) } const resolveComponentStubByName = ( diff --git a/src/utils/find.ts b/src/utils/find.ts index 486a217f3..cef6cb8d1 100644 --- a/src/utils/find.ts +++ b/src/utils/find.ts @@ -8,6 +8,7 @@ import { FindAllComponentsSelector } from '../types' import { getOriginalVNodeTypeFromStub } from '../stubs' import { isComponent } from '../utils' import { matchName } from './matchName' +import { convertLegacyVueExtendSelector } from './vueCompatSupport' /** * Detect whether a selector matches a VNode @@ -17,8 +18,10 @@ import { matchName } from './matchName' */ export function matches( node: VNode, - selector: FindAllComponentsSelector + rawSelector: FindAllComponentsSelector ): boolean { + const selector = convertLegacyVueExtendSelector(rawSelector) + // do not return none Vue components if (!node.component) return false diff --git a/src/utils/vueCompatSupport.ts b/src/utils/vueCompatSupport.ts new file mode 100644 index 000000000..194e46304 --- /dev/null +++ b/src/utils/vueCompatSupport.ts @@ -0,0 +1,21 @@ +import * as Vue from 'vue' +import type { ComponentOptions } from 'vue' +import { FindAllComponentsSelector } from '../types' + +function isCompatEnabled(key: string): boolean { + return (Vue as any).compatUtils?.isCompatEnabled(key) ?? false +} + +export function convertLegacyVueExtendSelector( + selector: FindAllComponentsSelector +): FindAllComponentsSelector { + if (!isCompatEnabled('GLOBAL_EXTEND') || typeof selector !== 'function') { + return selector + } + + // @ts-ignore Vue.extend is part of Vue2 compat API, types are missing + const fakeCmp = Vue.extend({}) + + // @ts-ignore TypeScript does not allow access of properties on functions + return fakeCmp.super === selector.super ? selector.options : selector +} diff --git a/tests-compat/compat.spec.ts b/tests-compat/compat.spec.ts new file mode 100644 index 000000000..11fff69ef --- /dev/null +++ b/tests-compat/compat.spec.ts @@ -0,0 +1,38 @@ +import * as Vue from '@vue/compat' +import { mount } from '../src' + +const { configureCompat, extend, defineComponent } = Vue as any + +describe('@vue/compat build', () => { + it.each([true, false])( + 'correctly renders transition when RENDER_FUNCTION compat is %p', + (RENDER_FUNCTION) => { + configureCompat({ MODE: 3, RENDER_FUNCTION }) + + const Component = defineComponent({ + template: '
' + }) + const wrapper = mount(Component) + + expect(wrapper.find('.hello').exists()).toBe(true) + } + ) + + it('finds components declared with legacy Vue.extend', () => { + configureCompat({ MODE: 3, GLOBAL_EXTEND: true }) + + const LegacyComponent = extend({ + template: '
LEGACY
' + }) + + const Component = defineComponent({ + components: { + LegacyComponent + }, + template: '
' + }) + const wrapper = mount(Component) + + expect(wrapper.findComponent(LegacyComponent).exists()).toBe(true) + }) +}) diff --git a/tests-compat/jest-compat.config.js b/tests-compat/jest-compat.config.js new file mode 100644 index 000000000..493a08872 --- /dev/null +++ b/tests-compat/jest-compat.config.js @@ -0,0 +1,8 @@ +const originalJestConfig = require('../jest.config') + +module.exports = { + ...originalJestConfig, + moduleNameMapper: { + '^vue$': '@vue/compat' + } +} diff --git a/types/compat.ts b/types/compat.ts new file mode 100644 index 000000000..397abd620 --- /dev/null +++ b/types/compat.ts @@ -0,0 +1,3 @@ +declare module '@vue/compat' { + export * from 'vue' +} diff --git a/yarn.lock b/yarn.lock index a395c8cba..6163f9df3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1795,6 +1795,11 @@ html-tags "^3.1.0" svg-tags "^1.0.0" +"@vue/compat@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@vue/compat/-/compat-3.1.2.tgz#066765421f2d872350f1faec841ceca32858111e" + integrity sha512-6pS22V01LmvkPMtpZvgk0udtR3pNTfxvFR+E4Ut+H9HHusyGf7Gx+PnQwnmawGOxuATNGzfasMaxIkQpbdT8jQ== + "@vue/compiler-core@3.1.1": version "3.1.1" resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.1.1.tgz#4f2c5d70eabd454675714cc8bd2b97f6a8efb196"