Skip to content

Commit

Permalink
feat!: use vue 2.7 composition api (#645)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Some of the API and behaviour differ between Vue 2.7 and `@vue/composition-api`. In addition, there are some composition utilites that are no longer exported from `@nuxtjs/composition-api`, such as `defineAsyncComponent`, `warn`, etc.

Please read https://blog.vuejs.org/posts/vue-2-7-naruto.html for the announcement and more information.

resolves #644, resolves #643, resolves #593, resolves #19
  • Loading branch information
danielroe committed Jul 8, 2022
1 parent 3066e46 commit ae9307a
Show file tree
Hide file tree
Showing 31 changed files with 3,215 additions and 4,689 deletions.
3 changes: 0 additions & 3 deletions .eslintrc.js
Expand Up @@ -4,9 +4,7 @@ module.exports = {
browser: true,
es6: true,
node: true,
'jest/globals': true,
},
plugins: ['jest'],
rules: {
'prettier/prettier': [
1,
Expand All @@ -26,6 +24,5 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
'prettier',
'plugin:jest/recommended',
],
}
13 changes: 0 additions & 13 deletions jest.config.js

This file was deleted.

33 changes: 13 additions & 20 deletions package.json
Expand Up @@ -19,11 +19,8 @@
},
"sideEffects": true,
"exports": {
".": {
"import": "./dist/runtime/index.mjs",
"require": "./dist/runtime/index.js"
},
"./module": "./dist/module/index.js",
".": "./dist/runtime/index.mjs",
"./module": "./dist/module/index.mjs",
"./package.json": "./package.json",
"./dist/babel-plugin": "./dist/babel-plugin/index.js",
"./dist/runtime/globals": "./dist/runtime/globals.js",
Expand Down Expand Up @@ -58,45 +55,40 @@
"test:e2e-globals": "cross-env GLOBALS=true PORT=3000 start-server-and-test fixture:prod 3000 \"testcafe firefox:headless test/e2e\"",
"test:e2e-ssr": "cross-env PORT=4000 start-server-and-test fixture:prod 4000 \"testcafe firefox:headless test/e2e\"",
"test:types": "tsd",
"test:unit": "jest",
"test:unit": "vitest run",
"watch": "yarn build -w"
},
"dependencies": {
"@vue/composition-api": "^1.6.0",
"defu": "^5.0.1",
"estree-walker": "^2.0.2",
"fs-extra": "^9.1.0",
"magic-string": "^0.26.1",
"ufo": "^0.8.3",
"unplugin-vue2-script-setup": "^0.10.2",
"upath": "^2.0.1"
},
"devDependencies": {
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/preset-typescript": "^7.16.7",
"@babel/traverse": "^7.18.6",
"@babel/types": "^7.18.6",
"@nuxt/test-utils": "^0.2.2",
"@nuxt/types": "^2.15.8",
"@nuxt/typescript-build": "^2.1.0",
"@nuxtjs/module-test-utils": "^1.6.3",
"@nuxtjs/pwa": "^3.3.5",
"@release-it/conventional-changelog": "^4.3.0",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.4.1",
"@types/normalize-path": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^5.21.0",
"@typescript-eslint/parser": "^5.21.0",
"babel-loader": "^8.2.5",
"c8": "^7.11.3",
"codecov": "^3.8.3",
"core-js": "3.22.2",
"cross-env": "^7.0.3",
"eslint": "^8.14.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-jest": "^26.1.5",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^6.0.0",
"happy-dom": "^6.0.2",
"http-server": "^14.1.0",
"jest": "^27.5.1",
"lint-staged": "^12.4.1",
"npm-run-all": "^4.1.5",
"nuxt": "^2.15.8",
Expand All @@ -109,15 +101,19 @@
"ts-loader": "^8.4.0",
"tsd": "^0.20.0",
"typescript": "4.6.3",
"vitest": "^0.17.0",
"yorkie": "^2.0.0"
},
"peerDependencies": {
"@nuxt/vue-app": "^2.15",
"nuxt": "^2.15",
"vue": "^2"
"vue": "^2.7.4"
},
"engines": {
"node": "^12.20.0 || >=14.13.0"
"node": ">=14.13.0"
},
"volta": {
"node": "16.16.0"
},
"gitHooks": {
"pre-commit": "lint-staged"
Expand All @@ -127,8 +123,5 @@
"compilerOptions": {
"rootDir": "."
}
},
"volta": {
"node": "16.16.0"
}
}
42 changes: 2 additions & 40 deletions src/module/index.ts
@@ -1,6 +1,5 @@
import type { Module, NuxtOptions } from '@nuxt/types'
import { resolve } from 'upath'
import type { Configuration } from 'webpack'

import { name, version } from '../../package.json'

Expand All @@ -17,7 +16,7 @@ const compositionApiModule: Module<never> = function compositionApiModule() {

// Force transpilation of this library (to enable resolution of globals file)

const runtimeDir = resolve(__dirname, 'runtime')
const runtimeDir = resolve(__dirname, '../runtime')
nuxt.options.build.transpile = nuxt.options.build.transpile || []
nuxt.options.build.transpile.push('@nuxtjs/composition-api', runtimeDir)

Expand Down Expand Up @@ -57,28 +56,6 @@ const compositionApiModule: Module<never> = function compositionApiModule() {
vue: vueEntry,
}

// Define @vue/composition-api resolution to prevent using different versions of @vue/composition-api

const capiEntrypoint = '@vue/composition-api/dist/vue-composition-api.mjs'
const capiResolution =
nuxt.options.alias['@vue/composition-api'] ||
this.nuxt.resolver.resolveModule(capiEntrypoint)

const capiAliases = Object.fromEntries(
['.common', '', '.prod', '.common.prod', '.esm', '.mjs']
.flatMap(m => [
`@vue/composition-api/dist/vue-composition-api${m}`,
`@vue/composition-api/dist/vue-composition-api${m}.js`,
])
.map(m => [m, capiResolution])
)

nuxt.options.alias = {
...capiAliases,
...nuxt.options.alias,
'@vue/composition-api': capiResolution,
}

// Define @nuxtjs/composition-api resolution to ensure plugins register global context successfully

nuxt.options.alias['@nuxtjs/composition-api'] =
Expand All @@ -87,16 +64,6 @@ const compositionApiModule: Module<never> = function compositionApiModule() {
.resolveModule('@nuxtjs/composition-api')
.replace('.js', '.mjs')

// Register the Vue Composition API for webpack

const registration = addResolvedTemplate.call(this, 'register.mjs')
this.nuxt.hook('webpack:config', (config: Configuration[]) => {
config.forEach(config => {
const entry = config.entry as Record<string, string[]>
entry.app.unshift(registration)
})
})

// Turn off webpack4 module context for .mjs files (as it appears to have some issues)

this.extendBuild(config => {
Expand All @@ -115,13 +82,11 @@ const compositionApiModule: Module<never> = function compositionApiModule() {
})
})

// If we're using nuxt-vite, register vite plugin & inject configuration
// If we're using nuxt-vite, register vite plugin for injecting keys

const viteMiddleware = addResolvedTemplate.call(this, 'middleware.mjs')
this.nuxt.hook('vite:extend', async (ctx: any) => {
const { compositionApiPlugin } = await import('./vite-plugin')
ctx.config.plugins.push(compositionApiPlugin())
ctx.config.resolve.alias['./middleware.js'] = viteMiddleware
})

// If we're using Babel, register Babel plugin for injecting keys
Expand All @@ -145,9 +110,6 @@ const compositionApiModule: Module<never> = function compositionApiModule() {
nuxt.options.plugins.unshift(globalPlugin)
})

// Enable using `script setup`
this.addModule('unplugin-vue2-script-setup/nuxt')

if (!this.nuxt.options.capi?.disableMigrationWarning) {
this.nuxt.hook('build:done', () => {
console.info(
Expand Down
3 changes: 1 addition & 2 deletions src/module/utils.ts
Expand Up @@ -27,10 +27,9 @@ export function addResolvedTemplate(
const nuxtOptions: NuxtOptions = this.nuxt.options

const src = resolveRelativePath(`../runtime/templates/${template}`)
const filename = template.replace('register.mjs', 'register.js')
const { dst } = this.addTemplate({
src,
fileName: join('composition-api', filename),
fileName: join('composition-api', template),
options,
})

Expand Down
4 changes: 2 additions & 2 deletions src/runtime/composables/async.ts
@@ -1,5 +1,5 @@
import { isRef, onServerPrefetch } from '@vue/composition-api'
import type { Ref } from '@vue/composition-api'
import { isRef, onServerPrefetch } from 'vue'
import type { Ref } from 'vue'

import { globalNuxt } from '@nuxtjs/composition-api/dist/runtime/globals'
import { ssrRef } from './ssr-ref'
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/composables/component.ts
@@ -1,4 +1,4 @@
import { defineComponent as define } from '@vue/composition-api'
import { defineComponent as define } from 'vue'

import { getHeadOptions } from './meta'

Expand Down
4 changes: 2 additions & 2 deletions src/runtime/composables/context.ts
@@ -1,6 +1,6 @@
import { computed } from '@vue/composition-api'
import { computed } from 'vue'

import type { Ref } from '@vue/composition-api'
import type { Ref } from 'vue'
import type { Context } from '@nuxt/types'
import type { Route } from 'vue-router'

Expand Down
43 changes: 24 additions & 19 deletions src/runtime/composables/fetch.ts
Expand Up @@ -4,8 +4,9 @@ import {
onBeforeMount,
onServerPrefetch,
reactive,
ComponentInstance,
set,
} from '@vue/composition-api'
} from 'vue'

import {
globalContext,
Expand All @@ -14,7 +15,7 @@ import {
} from '@nuxtjs/composition-api/dist/runtime/globals'
import type { NuxtApp } from '@nuxt/types/app'

import { getCurrentInstance, ComponentInstance } from './utils'
import { getCurrentInstance } from './utils'

const nuxtState = process.client && (window as any)[globalContext]

Expand Down Expand Up @@ -135,29 +136,30 @@ const mergeDataOnMount = (data: Record<string, any>) => {
if (!vm) throw new Error('This must be called within a setup function.')

onBeforeMount(() => {
const vmData = (vm as any)._setupProxy || vm
// Merge data
for (const key in data) {
try {
// Assign missing properties
if (key in vm) {
const _key = key as keyof typeof vm
if (key in vmData) {
const _key = key as keyof typeof vmData
// Skip value equal to incoming data
if (vm[_key] === data[key]) continue
if (vmData[_key] === data[key]) continue
// Skip functions (not stringifiable)
if (typeof vm[_key] === 'function') continue
if (typeof vmData[_key] === 'function') continue
// Preserve reactive objects
if (isReactive(vm[_key])) {
if (isReactive(vmData[_key])) {
// Unset keys that do not exist in incoming data
for (const k in vm[_key]) {
for (const k in vmData[_key]) {
if (!(k in data[key])) {
delete vm[_key][k]
delete vmData[_key][k]
}
}
Object.assign(vm[_key], data[key])
Object.assign(vmData[_key], data[key])
continue
}
}
set(vm, key, data[key])
set(vmData, key, data[key])
} catch (e) {
if (process.env.NODE_ENV === 'development')
// eslint-disable-next-line
Expand Down Expand Up @@ -219,14 +221,17 @@ async function serverPrefetch(vm: AugmentedComponentInstance) {
if (!vm.$vnode.data) vm.$vnode.data = {}
const attrs = (vm.$vnode.data.attrs = vm.$vnode.data.attrs || {})
attrs['data-fetch-key'] = vm._fetchKey

const data = { ...vm._data }
Object.entries((vm as any).__composition_api_state__.rawBindings).forEach(
([key, val]) => {
if (val instanceof Function || val instanceof Promise) return

data[key] = isRef(val) ? val.value : val
}
const data = Object.fromEntries(
Object.entries((vm as any)?._setupProxy || (vm as any)?._setupState)
.filter(
([_key, val]) =>
!(
(val && typeof val === 'object' && '_compiled' in val) ||
val instanceof Function ||
val instanceof Promise
)
)
.map(([key, val]) => [key, isRef(val) ? val.value : val])
)

// Add to ssrContext for window.__NUXT__.fetch
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/composables/hooks.ts
@@ -1,5 +1,5 @@
import type { Plugin } from '@nuxt/types'
import type { SetupContext } from '@vue/composition-api'
import type { SetupContext } from 'vue'
import { getHeadOptions } from './meta'

import { reqRefs } from './req-ref'
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/composables/meta.ts
Expand Up @@ -10,7 +10,7 @@ import {
isRef,
toRaw,
UnwrapRef,
} from '@vue/composition-api'
} from 'vue'

import type { MetaInfo } from 'vue-meta'

Expand Down
2 changes: 1 addition & 1 deletion src/runtime/composables/req-ref.ts
@@ -1,4 +1,4 @@
import { ref, Ref } from '@vue/composition-api'
import { ref, Ref } from 'vue'

import { sanitise, ssrRef } from './ssr-ref'

Expand Down
9 changes: 2 additions & 7 deletions src/runtime/composables/ssr-ref.ts
@@ -1,10 +1,5 @@
import {
customRef,
onServerPrefetch,
ref,
shallowRef,
} from '@vue/composition-api'
import type { Ref } from '@vue/composition-api'
import { customRef, onServerPrefetch, ref, shallowRef } from 'vue'
import type { Ref } from 'vue'

import {
globalContext,
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/composables/static.ts
@@ -1,5 +1,5 @@
import { onServerPrefetch, watch, computed, ref } from '@vue/composition-api'
import type { Ref } from '@vue/composition-api'
import { onServerPrefetch, watch, computed, ref } from 'vue'
import type { Ref } from 'vue'

import { joinURL } from 'ufo'

Expand Down Expand Up @@ -115,6 +115,7 @@ export const useStatic = <T>(
},
{
immediate: true,
flush: 'post',
}
)
} else {
Expand Down

0 comments on commit ae9307a

Please sign in to comment.