Skip to content
This repository was archived by the owner on Dec 25, 2024. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: unplugin/unplugin-vue2-script-setup
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.2.0
Choose a base ref
...
head repository: unplugin/unplugin-vue2-script-setup
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref

Commits on Aug 21, 2021

  1. Copy the full SHA
    1127f68 View commit details
  2. chore: update

    antfu committed Aug 21, 2021
    Copy the full SHA
    219ba50 View commit details
  3. docs: update docs

    antfu committed Aug 21, 2021
    Copy the full SHA
    c834119 View commit details
  4. docs: update

    antfu committed Aug 21, 2021
    Copy the full SHA
    03b03cf View commit details

Commits on Aug 22, 2021

  1. 1
    Copy the full SHA
    be5be03 View commit details
  2. release v0.2.1

    antfu committed Aug 22, 2021
    Copy the full SHA
    a81cda4 View commit details
  3. fix: v-for parsing

    antfu committed Aug 22, 2021
    Copy the full SHA
    cc9ea92 View commit details
  4. release v0.2.2

    antfu committed Aug 22, 2021
    Copy the full SHA
    98cf455 View commit details
  5. fix(parser): handle more cases

    antfu committed Aug 22, 2021
    Copy the full SHA
    1c42237 View commit details
  6. release v0.2.3

    antfu committed Aug 22, 2021
    Copy the full SHA
    f81b6fb View commit details
  7. fix(parser): hanlde more cases

    antfu committed Aug 22, 2021
    Copy the full SHA
    e1276bb View commit details
  8. release v0.2.4

    antfu committed Aug 22, 2021
    Copy the full SHA
    8f0c9ed View commit details
  9. Copy the full SHA
    5b2131a View commit details
  10. test: add more tests

    antfu committed Aug 22, 2021
    Copy the full SHA
    df12acc View commit details
  11. fix: macros without variables

    antfu committed Aug 22, 2021
    Copy the full SHA
    569fca5 View commit details
  12. docs: add vue-cli example, close #10

    antfu committed Aug 22, 2021
    Copy the full SHA
    8f97185 View commit details
  13. release v0.2.5

    antfu committed Aug 22, 2021
    Copy the full SHA
    d06c3b7 View commit details
  14. docs: update link

    antfu committed Aug 22, 2021
    Copy the full SHA
    8c2e2a4 View commit details
  15. Copy the full SHA
    3f5dcf5 View commit details
  16. fix: sub module types

    antfu committed Aug 22, 2021
    Copy the full SHA
    8357d2e View commit details
  17. release v0.2.6

    antfu committed Aug 22, 2021
    Copy the full SHA
    0437983 View commit details
  18. Copy the full SHA
    e0b0a78 View commit details
  19. Copy the full SHA
    cd24f26 View commit details
  20. release v0.3.0

    antfu committed Aug 22, 2021
    Copy the full SHA
    df21484 View commit details
  21. Copy the full SHA
    e6343b3 View commit details
  22. fix(types): export types

    antfu committed Aug 22, 2021
    Copy the full SHA
    363b797 View commit details
  23. release v0.3.1

    antfu committed Aug 22, 2021
    Copy the full SHA
    a155fb0 View commit details
  24. chore: typo

    antfu committed Aug 22, 2021
    Copy the full SHA
    4c14b45 View commit details

Commits on Aug 23, 2021

  1. Update README.md

    antfu authored Aug 23, 2021
    Copy the full SHA
    25c63d1 View commit details
  2. chore: update exports

    antfu committed Aug 23, 2021
    Copy the full SHA
    20ca4bd View commit details
  3. release v0.3.2

    antfu committed Aug 23, 2021
    Copy the full SHA
    232709d View commit details
  4. fix: throw on top-level await

    antfu committed Aug 23, 2021
    Copy the full SHA
    e98500d View commit details
  5. Copy the full SHA
    bf3dfee View commit details
  6. release v0.3.3

    antfu committed Aug 23, 2021
    Copy the full SHA
    5648b44 View commit details
  7. Copy the full SHA
    486f157 View commit details
  8. release v0.3.4

    antfu committed Aug 23, 2021
    Copy the full SHA
    af118b2 View commit details
  9. Copy the full SHA
    7c0fd3e View commit details
  10. release v0.3.5

    antfu committed Aug 23, 2021
    Copy the full SHA
    1d37e07 View commit details
  11. Copy the full SHA
    f052591 View commit details
  12. docs: vue-cli with ts, close #14

    antfu committed Aug 23, 2021
    Copy the full SHA
    ef9b63c View commit details

Commits on Aug 24, 2021

  1. Copy the full SHA
    4af8ae4 View commit details
  2. release v0.4.0

    antfu committed Aug 24, 2021
    Copy the full SHA
    1af58c7 View commit details
  3. Copy the full SHA
    f09aae6 View commit details
  4. release v0.4.1

    antfu committed Aug 24, 2021
    Copy the full SHA
    a2a773c View commit details
  5. Update README.md

    antfu authored Aug 24, 2021
    Copy the full SHA
    d1006d2 View commit details

Commits on Aug 25, 2021

  1. fix: v-for parsing, close #22

    antfu committed Aug 25, 2021
    Copy the full SHA
    c9fbb09 View commit details
  2. release v0.4.2

    antfu committed Aug 25, 2021
    Copy the full SHA
    e9951d9 View commit details

Commits on Aug 26, 2021

  1. fix: script setup check (#24)

    sxzz authored Aug 26, 2021
    Copy the full SHA
    5ce5786 View commit details
  2. feat: support ref sugar (#23)

    Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
    sxzz and antfu authored Aug 26, 2021
    Copy the full SHA
    ef5bb09 View commit details
  3. feat: expose more options

    antfu committed Aug 26, 2021
    Copy the full SHA
    a1829d6 View commit details
Showing with 10,775 additions and 10,495 deletions.
  1. +1 −0 .eslintignore
  2. +0 −8 .eslintrc
  3. +3 −0 .eslintrc.json
  4. +3 −1 .github/workflows/release.yml
  5. +19 −10 .github/workflows/test.yml
  6. +1 −0 .gitignore
  7. +2 −1 .npmrc
  8. +6 −0 .tazerc.json
  9. +230 −32 README.md
  10. +1 −0 esbuild.d.ts
  11. +0 −38 examples/nuxt/components/HelloWorld.vue
  12. +0 −7 examples/nuxt/nuxt.config.js
  13. +0 −21 examples/nuxt/package.json
  14. +0 −13 examples/nuxt/pages/index.vue
  15. +0 −33 examples/nuxt/tsconfig.json
  16. +1 −0 examples/vue-cli/.npmrc
  17. +5 −0 examples/vue-cli/babel.config.js
  18. +24 −0 examples/vue-cli/package.json
  19. +16 −0 examples/vue-cli/public/index.html
  20. +18 −0 examples/vue-cli/src/App.vue
  21. +51 −0 examples/vue-cli/src/components/HelloWorld.vue
  22. +12 −0 examples/vue-cli/src/main.ts
  23. +1 −0 examples/vue-cli/src/shims-vue.d.ts
  24. +31 −0 examples/vue-cli/tsconfig.json
  25. +23 −0 examples/vue-cli/vue.config.cjs
  26. +0 −181 global.d.ts
  27. +1 −2 index.d.ts
  28. +0 −12 jest.config.js
  29. +22 −0 jest.js
  30. +1 −2 nuxt.d.ts
  31. +107 −61 package.json
  32. +0 −13 playground/App.vue
  33. +0 −38 playground/HelloWorld.vue
  34. +1 −1 playground/index.html
  35. +0 −10 playground/main.ts
  36. +7 −7 playground/package.json
  37. +21 −0 playground/src/App.vue
  38. +3 −0 playground/src/Async.vue
  39. +3 −0 playground/src/Bar.vue
  40. +11 −0 playground/src/ButtonTest.vue
  41. +8 −0 playground/src/Foo.vue
  42. +42 −0 playground/src/HelloWorld.vue
  43. +9 −0 playground/src/main.ts
  44. +2 −0 playground/src/shims-vue.d.ts
  45. +31 −0 playground/tsconfig.json
  46. +6 −2 playground/vite.config.ts
  47. +6,977 −9,580 pnpm-lock.yaml
  48. +77 −0 ref-macros.d.ts
  49. +89 −0 rollup.config.mjs
  50. +1 −0 rollup.d.ts
  51. +23 −0 scripts/postbuild.ts
  52. +6 −0 shims.d.ts
  53. +9 −0 src/core/babel.ts
  54. +132 −0 src/core/identifiers.ts
  55. +3 −0 src/core/index.ts
  56. +71 −23 src/{ → core}/macros.ts
  57. +14 −0 src/core/options.ts
  58. +402 −0 src/core/parseSFC.ts
  59. +82 −0 src/core/transform.ts
  60. +235 −0 src/core/transformScriptSetup.ts
  61. +27 −0 src/core/transformSfcRefSugar.ts
  62. +9 −0 src/core/utils.ts
  63. +3 −0 src/esbuild.ts
  64. +31 −1 src/index.ts
  65. +1 −0 src/lib.ts
  66. +11 −6 src/nuxt.ts
  67. +0 −126 src/parse.ts
  68. +3 −0 src/rollup.ts
  69. +0 −30 src/transform.ts
  70. +0 −152 src/transformScriptSetup.ts
  71. +47 −8 src/types.ts
  72. +0 −15 src/vite-plugin.ts
  73. +3 −0 src/vite.ts
  74. +0 −16 src/webpack-plugin.ts
  75. +3 −0 src/webpack.ts
  76. +1,003 −31 test/__snapshots__/transform.test.ts.snap
  77. +63 −0 test/errors.test.ts
  78. +8 −0 test/fixtures/AsyncImport.vue
  79. +57 −0 test/fixtures/ComponentsDirectives.vue
  80. +13 −0 test/fixtures/ComponentsDirectivesLocal.vue
  81. +7 −0 test/fixtures/ComponentsLocal.vue
  82. +7 −0 test/fixtures/DynamicStyle.vue
  83. 0 test/fixtures/Empty.vue
  84. +9 −0 test/fixtures/Enum.vue
  85. +20 −0 test/fixtures/HtmlTag.vue
  86. +20 −0 test/fixtures/HtmlTag2.vue
  87. +7 −0 test/fixtures/JSLongComment.vue
  88. +11 −0 test/fixtures/Macros.vue
  89. +14 −0 test/fixtures/MacrosDefineExpose.vue
  90. +10 −0 test/fixtures/MacrosPure.vue
  91. +14 −0 test/fixtures/MacrosType.vue
  92. +25 −0 test/fixtures/MacrosType2.vue
  93. +15 −0 test/fixtures/MacrosType3.vue
  94. +7 −0 test/fixtures/MacrosType4.vue
  95. +5 −0 test/fixtures/MacrosType5.vue
  96. +13 −0 test/fixtures/MacrosType6.vue
  97. +9 −0 test/fixtures/MacrosTypeAny.vue
  98. +11 −0 test/fixtures/Object1.vue
  99. +9 −0 test/fixtures/ObjectDestructure.vue
  100. +13 −0 test/fixtures/Pug1.vue
  101. +14 −0 test/fixtures/RefSugar.ts
  102. +31 −0 test/fixtures/RefSugar.vue
  103. +11 −0 test/fixtures/RefSugarScriptSetup.vue
  104. +7 −0 test/fixtures/ScriptLessThanOrEqualTo.vue
  105. +10 −0 test/fixtures/ScriptOnly.vue
  106. +16 −0 test/fixtures/TemplateOnly.vue
  107. +19 −0 test/fixtures/TemplateOptionalChaining.vue
  108. +25 −0 test/fixtures/VFor.vue
  109. +22 −0 test/fixtures/VariableBinding.vue
  110. +71 −0 test/identifiers.test.ts
  111. +91 −0 test/nativeTag.test.ts
  112. +24 −9 test/transform.test.ts
  113. +75 −0 test/transform_filter.test.ts
  114. +4 −1 tsconfig.json
  115. +1 −0 types.d.ts
  116. +0 −2 vite-plugin.d.ts
  117. +1 −0 vite.d.ts
  118. +0 −2 webpack-plugin.d.ts
  119. +1 −0 webpack.d.ts
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
dist
node_modules
*.vue
8 changes: 0 additions & 8 deletions .eslintrc

This file was deleted.

3 changes: 3 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@antfu"
}
4 changes: 3 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -8,13 +8,15 @@ on:
jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-node@v2
with:
node-version: '14'
node-version: lts/*
registry-url: https://registry.npmjs.org/
- run: npm i -g pnpm @antfu/ni
- run: nci
29 changes: 19 additions & 10 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -17,26 +17,35 @@ jobs:

strategy:
matrix:
node-version: [12.x, 14.x]
node: [18.x]
os: [ubuntu-latest, windows-latest, macos-latest]
fail-fast: false

steps:
- uses: actions/checkout@v2

- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
- name: Install pnpm
uses: pnpm/action-setup@v2

- name: Set node version to ${{ matrix.node }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
node-version: ${{ matrix.node }}
cache: pnpm

- name: Setup
run: npm i -g pnpm @antfu/ni
- uses: actions/checkout@v2

- name: Install
run: nci
run: pnpm i

# - name: Lint
# run: nr lint --if-present
- name: Lint
run: pnpm run lint

- name: Build
run: pnpm run build

- name: Test
run: nr test --if-present
run: pnpm run test

- name: Build Examples
run: pnpm run build:examples
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -81,3 +81,4 @@ dist
.idea

temp.ts
.output
3 changes: 2 additions & 1 deletion .npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
shamefully-hoist=true
ignore-workspace-root-check=true
strict-peer-dependencies=false
6 changes: 6 additions & 0 deletions .tazerc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"exclude": [
"vue",
"htmlparser2"
]
}
262 changes: 230 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
# vue2-script-setup-transform
# unplugin-vue2-script-setup

[![NPM version](https://img.shields.io/npm/v/vue2-script-setup-transform?color=a1b858&label=)](https://www.npmjs.com/package/vue2-script-setup-transform)
[![NPM version](https://img.shields.io/npm/v/unplugin-vue2-script-setup?color=a1b858&label=)](https://www.npmjs.com/package/unplugin-vue2-script-setup)

Bring [`<script setup>`](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md) to Vue 2.
Bring [`<script setup>`](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to Vue 2. Works for Vite, Nuxt, Vue CLI, Webpack, esbuild and more, powered by [unplugin](https://github.com/unjs/unplugin).

> ⚠️ With the release of [Vue 2.7](https://blog.vuejs.org/posts/vue-2-7-naruto.html), which has Composition API and `<script setup>` built-in, **you no longer need this plugin**. Thereby this plugin has entered maintenance mode and will only support Vue 2.6 or earlier. This project will reach End of Life by the end of 2022.
## Install

```bash
npm i -D vue2-script-setup-transform
npm i -D unplugin-vue2-script-setup
npm i @vue/composition-api
```

Install [`@vue/composition-api`](https://github.com/vuejs/composition-api) in your App's entry (this enables the `setup()` hook).
Install [`@vue/composition-api`](https://github.com/vuejs/composition-api) in your App's entry (it enables the `setup()` hook):

```ts
import Vue from 'vue'
@@ -20,62 +22,172 @@ import VueCompositionAPI from '@vue/composition-api'
Vue.use(VueCompositionAPI)
```

See [`playground/`](./playground/) as an example.

###### Vite
<details>
<summary>Vite</summary><br>

```ts
// vite.config.ts
import { defineConfig } from 'vite'
import { createVuePlugin as Vue2 } from 'vite-plugin-vue2'
import ScriptSetup from 'vue2-script-setup-transform/vite-plugin'
import ScriptSetup from 'unplugin-vue2-script-setup/vite'

export default defineConfig({
plugins: [
Vue2(),
ScriptSetup(),
ScriptSetup({ /* options */ }),
],
})
```

###### Nuxt
Example: [`playground/`](./playground/)

<br></details>

<details>
<summary>Nuxt</summary><br>

> It's built-in in [Nuxt Bridge](https://github.com/nuxt/bridge).
</details>

<details>
<summary>Vue CLI</summary><br>

```ts
// vue.config.js
const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default

module.exports = {
parallel: false, // disable thread-loader, which is not compactible with this plugin
configureWebpack: {
plugins: [
ScriptSetup({ /* options */ }),
],
},
}
```

Example: [`examples/vue-cli`](./examples/vue-cli)

###### TypeScript

To use TypeScript with Vue CLI, install `@vue/cli-plugin-typescript` but disable the type check:

```bash
npm i @nuxtjs/composition-api
npm i -D @vue/cli-plugin-typescript vue-tsc
```

```ts
// nuxt.config.js
export default {
buildModules: [
'@nuxtjs/composition-api/module',
'vue2-script-setup-transform/nuxt',
],
const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default

module.exports = {
parallel: false,
configureWebpack: {
plugins: [
ScriptSetup({ /* options */ }),
],
},
chainWebpack(config) {
// disable type check and let `vue-tsc` handles it
config.plugins.delete('fork-ts-checker')
},
}
```

See [`examples/nuxt`](./examples/nuxt).
And then use [`vue-tsc`](https://github.com/johnsoncodehk/volar) to do the type check at build time:

```jsonc
// package.json
{
"scripts": {
"dev": "vue-cli-service serve",
"build": "vue-tsc --noEmit && vue-cli-service build"
}
}
```

###### Webpack
<br></details>

<details>
<summary>Webpack</summary><br>

```ts
// webpack.config.js
import ScriptSetup from 'vue2-script-setup-transform/webpack-plugin'
const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default

module.exports = {
/* ... */
plugins: [
ScriptSetup()
ScriptSetup({ /* options */ }),
]
}
```

<br></details>

<details>
<summary>Rollup</summary><br>

```ts
// rollup.config.js
import Vue from 'rollup-plugin-vue'
import ScriptSetup from 'unplugin-vue2-script-setup/rollup'

export default {
plugins: [
Vue(),
ScriptSetup({ /* options */ }),
]
}
```

###### JavaScript API
<br></details>

<details>
<summary>esbuild</summary><br>

```ts
// esbuild.config.js
import { build } from 'esbuild'
import ScriptSetup from 'unplugin-vue2-script-setup/esbuild'

build({
/* ... */
plugins: [
ScriptSetup({
/* options */
}),
],
})
```

<br></details>

<details>
<summary>Jest</summary><br>

```bash
npm i -D vue-jest
```

```ts
// jest.config.js
module.exports = {
transform: {
'.*\\.(vue)$': 'unplugin-vue2-script-setup/jest',
},
}
```

<br></details>

<details>
<summary>JavaScript API</summary><br>

```ts
import { transform } from 'vue2-script-setup-transform'
import { transform } from 'unplugin-vue2-script-setup'

const Vue2SFC = transform(`
const Vue2SFC = await transform(`
<template>
<!-- ... -->
</template>
@@ -86,16 +198,102 @@ const Vue2SFC = transform(`
`)
```

## Status
<br></details>

## IDE

We recommend using [VS Code](https://code.visualstudio.com/) with [Volar](https://github.com/johnsoncodehk/volar) to get the best experience (You might want to disable Vetur if you have it).

When using Volar, you need to install `@vue/runtime-dom` as devDependencies to make it work on Vue 2.

- [x] POC
```bash
npm i -D @vue/runtime-dom
```

[Learn more](https://github.com/johnsoncodehk/volar#using)

###### Global Types

If the global types are missing for your IDE, update your `tsconfig.json` with:

```jsonc
{
"compilerOptions": {
"types": [
"unplugin-vue2-script-setup/types"
]
}
}
```

###### Support Vue 2 template

Volar preferentially supports Vue 3. Vue 3 and Vue 2 template has some different. You need to set the `experimentalCompatMode` option to support Vue 2 template.

```jsonc
{
"compilerOptions": {
// ...
},
"vueCompilerOptions": {
"target": 2
}
}
```

###### ESLint

If you are using ESLint, you might get `@typescript-eslint/no-unused-vars` warning with `<script setup>`. You can disable it and add `noUnusedLocals: true` in your `tsconfig.json`, Volar will infer the real missing locals correctly for you.

## Configurations

<details>
<summary>
Ref Sugar (take 2)
</summary>

In v0.5.x, we shipped the **experimental** [Ref Sugar (take 2)](https://github.com/vuejs/rfcs/discussions/369) implementation based on Vue 3's [`@vue/reactivity-transform`](https://github.com/vuejs/vue-next/tree/master/packages/reactivity-transform) package. Notice the syntax is not settled yet and might be changed in the future updates. **Use at your own risk!**

To enabled it, pass the option:

```ts
ScriptSetup({
reactivityTransform: true
})
```

To get TypeScript support, update your `tsconfig.json` with:

```jsonc
{
"compilerOptions": {
"types": [
"unplugin-vue2-script-setup/types",
"unplugin-vue2-script-setup/ref-macros"
]
}
}
```

</details>

## Recommendations

If you enjoy using `<script setup>`, you might also want to try [`unplugin-auto-import`](https://github.com/antfu/unplugin-auto-import) to improve the DX even further.

## Progress

- [x] PoC
- [x] Components registration
- [x] Compile time macros `defineProps` `defineEmits` `withDefaults`
- [x] Compile time macros `defineProps` `defineEmits` `withDefaults` `defineExpose`
- [x] Global types
- [x] Merge with normal scripts
- [x] [Ref Sugar (take 2)](https://github.com/vuejs/rfcs/discussions/369)
- [x] `<template lang="pug">` support
- [x] Vite plugin
- [x] Webpack plugin
- [x] Global types
- [ ] Top-level await
- [x] Nuxt module
- [ ] ~~Top-level await~~ (not supported)

## How?

@@ -106,9 +304,9 @@ const Vue2SFC = transform(`

![image](https://user-images.githubusercontent.com/11247099/130307245-20f9342e-377b-4565-b55d-1b91741b5c0f.png)

It's made possible by transforming the SFC back to normal `<script>` and let the Vue 2 SFC compiler handle the rest.
It's made possible by transforming the `<script setup>` syntax back to normal `<script>` and let the Vue 2 SFC compiler handle the rest.

</details>
<br></details>

## Sponsors

1 change: 1 addition & 0 deletions esbuild.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './dist/esbuild'
38 changes: 0 additions & 38 deletions examples/nuxt/components/HelloWorld.vue

This file was deleted.

7 changes: 0 additions & 7 deletions examples/nuxt/nuxt.config.js

This file was deleted.

21 changes: 0 additions & 21 deletions examples/nuxt/package.json

This file was deleted.

13 changes: 0 additions & 13 deletions examples/nuxt/pages/index.vue

This file was deleted.

33 changes: 0 additions & 33 deletions examples/nuxt/tsconfig.json

This file was deleted.

1 change: 1 addition & 0 deletions examples/vue-cli/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
shamefully-hoist=true
5 changes: 5 additions & 0 deletions examples/vue-cli/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
],
}
24 changes: 24 additions & 0 deletions examples/vue-cli/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "vue-cli",
"private": true,
"scripts": {
"type-check": "vue-tsc --noEmit",
"dev": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"@vue/composition-api": "^1.7.1",
"core-js": "^3.32.0",
"vue": "~2.6.14"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-typescript": "^5.0.8",
"@vue/cli-service": "^5.0.8",
"typescript": "^5.1.6",
"unplugin-vue2-script-setup": "workspace:*",
"vue-template-compiler": "~2.6.14",
"vue-tsc": "^1.8.8"
}
}
16 changes: 16 additions & 0 deletions examples/vue-cli/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
18 changes: 18 additions & 0 deletions examples/vue-cli/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<script setup lang="ts">
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<div id="app">
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
51 changes: 51 additions & 0 deletions examples/vue-cli/src/components/HelloWorld.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<script setup lang="ts">
defineProps<{
msg: string
}>()
</script>
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-typescript" target="_blank" rel="noopener">typescript</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
12 changes: 12 additions & 0 deletions examples/vue-cli/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Vue from 'vue'
import VueCompositionAPI, { createApp, h } from '@vue/composition-api'
import App from './App.vue'

Vue.config.productionTip = false
Vue.use(VueCompositionAPI)

const app = createApp({
render: () => h(App),
})

app.mount('#app')
1 change: 1 addition & 0 deletions examples/vue-cli/src/shims-vue.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="unplugin-vue2-script-setup/shims.js" />
31 changes: 31 additions & 0 deletions examples/vue-cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"types": [
"webpack-env"
],
"lib": [
"esnext",
"dom",
"dom.iterable"
]
},
"include": [
"src"
],
"exclude": [
"node_modules"
],
"vueCompilerOptions": {
"target": 2
}
}
23 changes: 23 additions & 0 deletions examples/vue-cli/vue.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const { defineConfig } = require('@vue/cli-service')
const ScriptSetup = require('unplugin-vue2-script-setup/webpack').default

module.exports = defineConfig({
configureWebpack: {
plugins: [
ScriptSetup({
reactivityTransform: true,
}),
],
},
parallel: false,
chainWebpack(config) {
// disable type check and let `vue-tsc` handles it
config.plugins.delete('fork-ts-checker')

// disable cache for testing, you should remove this in production
config.module.rule('vue').uses.delete('cache-loader')
config.module.rule('js').uses.delete('cache-loader')
config.module.rule('ts').uses.delete('cache-loader')
config.module.rule('tsx').uses.delete('cache-loader')
},
})
181 changes: 0 additions & 181 deletions global.d.ts

This file was deleted.

3 changes: 1 addition & 2 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import './global'
export * from './dist/index'
export { default } from './dist/index'
12 changes: 0 additions & 12 deletions jest.config.js

This file was deleted.

22 changes: 22 additions & 0 deletions jest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { transform } = require('./dist/index')

function requireVueJest() {
const names = ['@vue/vue2-jest', 'vue-jest']
for (const name of names) {
try {
return require(name)
}
catch (e) {
// Try next module
}
}
throw new Error(`Cannot find a Jest transformer for Vue SFC, you should install one of these packages: ${names.join(', ')}`)
}

module.exports = {
async process(source, filename, ...args) {
const transformed = await transform(source, filename)
const code = transformed ? transformed.code : source
return requireVueJest().process.call(this, code, filename, ...args)
},
}
3 changes: 1 addition & 2 deletions nuxt.d.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
import './global'
export * from './dist/nuxt'
export { default } from './dist/nuxt'
168 changes: 107 additions & 61 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,81 +1,127 @@
{
"name": "vue2-script-setup-transform",
"version": "0.2.0",
"description": "",
"main": "dist/index.js",
"module": "dist/index.mjs",
"types": "index.d.ts",
"name": "unplugin-vue2-script-setup",
"version": "0.11.4",
"packageManager": "pnpm@8.6.11",
"description": "Bring <script setup> to Vue 2",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"funding": "https://github.com/sponsors/antfu",
"homepage": "https://github.com/unplugin/unplugin-vue2-script-setup#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/unplugin/unplugin-vue2-script-setup.git"
},
"bugs": {
"url": "https://github.com/unplugin/unplugin-vue2-script-setup/issues"
},
"exports": {
".": {
"require": "./dist/index.js",
"import": "./dist/index.mjs"
},
"./vite-plugin": {
"require": "./dist/vite-plugin.js",
"import": "./dist/vite-plugin.mjs"
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./webpack-plugin": {
"require": "./dist/webpack-plugin.js",
"import": "./dist/webpack-plugin.mjs"
"./*": "./*",
"./esbuild": {
"import": "./dist/esbuild.mjs",
"require": "./dist/esbuild.js"
},
"./jest": "./jest.js",
"./nuxt": {
"require": "./dist/nuxt.js",
"import": "./dist/nuxt.mjs"
"import": "./dist/nuxt.mjs",
"require": "./dist/nuxt.js"
},
"./rollup": {
"import": "./dist/rollup.mjs",
"require": "./dist/rollup.js"
},
"./types": {
"import": "./dist/types.mjs",
"require": "./dist/types.js"
},
"./vite": {
"import": "./dist/vite.mjs",
"require": "./dist/vite.js"
},
"./webpack": {
"import": "./dist/webpack.mjs",
"require": "./dist/webpack.js"
}
},
"funding": "https://github.com/sponsors/antfu",
"author": "Anthony Fu <anthonyfu117@hotmail.com>",
"license": "MIT",
"bugs": {
"url": "https://github.com/antfu/vue2-script-setup-transform/issues"
},
"homepage": "https://github.com/antfu/vue2-script-setup-transform#readme",
"repository": {
"type": "git",
"url": "git+https://github.com/antfu/vue2-script-setup-transform.git"
},
"keywords": [],
"main": "dist/index.js",
"files": [
"dist",
"jest.js",
"*.d.ts"
],
"scripts": {
"prepublishOnly": "nr build",
"dev": "nr build --watch",
"build": "rimraf dist && tsup src/index.ts src/vite-plugin.ts src/webpack-plugin.ts src/nuxt.ts --format cjs,esm --dts",
"build": "rimraf dist && rollup -c",
"dev": "rollup -c --watch",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"build:examples": "pnpm -r --filter=!unplugin-vue2-script-setup run build",
"play": "npm -C playground run dev",
"prepublishOnly": "nr build",
"release": "bumpp --commit --push --tag && pnpm publish",
"lint": "eslint \"{src,test}/**/*.ts\"",
"lint:fix": "nr lint -- --fix",
"test": "jest",
"test:update": "jest -u"
"test": "vitest",
"test:update": "vitest -u"
},
"devDependencies": {
"@antfu/eslint-config": "^0.7.0",
"@antfu/ni": "^0.7.0",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.1",
"@vue/composition-api": "^1.1.1",
"bumpp": "^6.0.6",
"eslint": "^7.32.0",
"eslint-plugin-jest": "^24.4.0",
"esno": "^0.9.1",
"jest": "^27.0.6",
"rimraf": "^3.0.2",
"ts-jest": "^27.0.5",
"tsup": "^4.14.0",
"typescript": "^4.3.5",
"vite": "^2.5.0"
"peerDependencies": {
"@vue/composition-api": "*",
"@vue/runtime-dom": "^3.2.31",
"pug": "^3.0.2"
},
"peerDependenciesMeta": {
"pug": {
"optional": true
}
},
"dependencies": {
"@babel/core": "^7.15.0",
"@babel/generator": "^7.15.0",
"@babel/parser": "^7.15.3",
"@babel/traverse": "^7.15.0",
"@babel/types": "^7.15.0",
"@vue/shared": "^3.2.4",
"htmlparser2": "^6.1.0",
"magic-string": "^0.25.7",
"unplugin": "^0.0.6"
"@antfu/utils": "^0.7.5",
"@babel/core": "^7.22.9",
"@babel/generator": "^7.22.9",
"@babel/parser": "^7.22.7",
"@babel/traverse": "^7.22.8",
"@babel/types": "^7.22.5",
"@rollup/pluginutils": "^5.0.2",
"@vue/compiler-core": "^3.3.4",
"@vue/compiler-dom": "^3.3.4",
"@vue/reactivity-transform": "^3.3.4",
"@vue/shared": "^3.3.4",
"defu": "^6.1.2",
"magic-string": "^0.30.2",
"unplugin": "^1.4.0"
},
"devDependencies": {
"@antfu/eslint-config": "^0.40.0",
"@antfu/ni": "^0.21.5",
"@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^25.0.3",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.1.0",
"@types/babel__core": "^7.20.1",
"@types/estree": "^1.0.1",
"@types/node": "^18.17.1",
"@types/pug": "^2.0.6",
"@types/ws": "^8.5.5",
"@vue/composition-api": "^1.7.1",
"@vue/runtime-dom": "^3.3.4",
"bumpp": "^9.1.1",
"esbuild": "^0.18.17",
"eslint": "^8.46.0",
"fast-glob": "^3.3.1",
"pug": "^3.0.2",
"rimraf": "^5.0.1",
"rollup": "^3.27.0",
"rollup-plugin-dts": "^5.3.1",
"rollup-plugin-esbuild": "^5.0.0",
"rollup-plugin-typescript2": "^0.35.0",
"typescript": "^5.1.6",
"vite": "^4.4.8",
"vitest": "^0.33.0",
"webpack": "^5.88.2"
},
"pnpm": {
"overrides": {
"unplugin-vue2-script-setup": "workspace:*"
}
}
}
13 changes: 0 additions & 13 deletions playground/App.vue

This file was deleted.

38 changes: 0 additions & 38 deletions playground/HelloWorld.vue

This file was deleted.

2 changes: 1 addition & 1 deletion playground/index.html
Original file line number Diff line number Diff line change
@@ -8,6 +8,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="./main.ts"></script>
<script type="module" src="./src/main.ts"></script>
</body>
</html>
10 changes: 0 additions & 10 deletions playground/main.ts

This file was deleted.

14 changes: 7 additions & 7 deletions playground/package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
{
"private": true,
"scripts": {
"dev": "vite --open"
"dev": "vite --open",
"build": "vite build"
},
"dependencies": {
"@vue/composition-api": "^1.1.1",
"@vue/composition-api": "^1.7.1",
"vue": "^2.6.14"
},
"devDependencies": {
"@vue/reactivity": "^3.2.4",
"vite": "^2.5.0",
"vite-plugin-inspect": "^0.2.2",
"vite-plugin-vue2": "^1.8.1",
"vue-template-compiler": "^2.6.14"
"vite": "^4.4.8",
"vite-plugin-inspect": "^0.7.35",
"vite-plugin-vue2": "^2.0.3",
"vue-template-compiler": "~2.6.14"
}
}
21 changes: 21 additions & 0 deletions playground/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<script setup lang="ts">
import { defineAsyncComponent } from '@vue/composition-api'
import ButtonTest from './ButtonTest.vue';
import HelloWorld from './HelloWorld.vue'
const AsyncComponent = defineAsyncComponent(() => import('./Async.vue'))
function onUpdate(e: any) {
// eslint-disable-next-line no-console
console.log(e)
}
</script>
<template>
<div>
<ButtonTest />

<HelloWorld name="Vue 2" @update="onUpdate" />

<AsyncComponent />
</div>
</template>
3 changes: 3 additions & 0 deletions playground/src/Async.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<div>Async Component</div>
</template>
3 changes: 3 additions & 0 deletions playground/src/Bar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<div>Bar</div>
</template>
11 changes: 11 additions & 0 deletions playground/src/ButtonTest.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
import Button from './Foo.vue';
import button from './Foo.vue';
</script>

<template>
<div>
<button>{{ Button }}</button>
<Button>{{ button }}</Button>
</div>
</template>
8 changes: 8 additions & 0 deletions playground/src/Foo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script setup lang="ts">
</script>
<template>
<div>
Button Component: <slot></slot>
</div>
</template>
42 changes: 42 additions & 0 deletions playground/src/HelloWorld.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script lang="ts">
/* eslint-disable import/first */
export default {
name: 'App',
}
</script>
<script setup lang="ts">
import { watch } from '@vue/composition-api'
import Foo from './Foo.vue'
import Bar from './Bar.vue'
withDefaults(defineProps<{ msg: string; name: string | number }>(), { msg: 'Hello' })
const emit = defineEmits<{
(event: 'update', value: number): void
}>()
let count = $ref(0)
// eslint-disable-next-line prefer-const
let doubled = $computed(() => count * 2)
function inc() {
count += 1
}
function dec() {
count -= 1
}
const decText = '<b>Dec</b>'
watch(count, value => emit('update', value))
</script>
<template>
<div>
<h3>{{ msg }}, {{ name }}</h3>
<button @click="inc">
Inc
</button>
<div>{{ count }} x 2 = {{ doubled }}</div>
<button @click="dec()" v-html="decText" />
<component :is="count > 2 ? Foo : Bar" />
</div>
</template>
9 changes: 9 additions & 0 deletions playground/src/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Vue from 'vue'
import VueCompositionAPI, { createApp, h } from '@vue/composition-api'
import App from './App.vue'

Vue.use(VueCompositionAPI)

const app = createApp({ render: () => h(App) })

app.mount('#app')
2 changes: 2 additions & 0 deletions playground/src/shims-vue.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// <reference types="unplugin-vue2-script-setup/shims.js" />
/// <reference types="unplugin-vue2-script-setup/ref-macros.js" />
31 changes: 31 additions & 0 deletions playground/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"skipLibCheck": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"types": [
"webpack-env"
],
"lib": [
"esnext",
"dom",
"dom.iterable"
]
},
"include": [
"src"
],
"exclude": [
"node_modules"
],
"vueCompilerOptions": {
"experimentalCompatMode": 2
}
}
8 changes: 6 additions & 2 deletions playground/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { defineConfig } from 'vite'
import { createVuePlugin as Vue2 } from 'vite-plugin-vue2'
import Inspect from 'vite-plugin-inspect'
import ScriptSetup from '../src/vite-plugin'
import { unplugin } from '../src'

const ScriptSetup = unplugin.vite

export default defineConfig({
plugins: [
Vue2(),
Inspect(),
ScriptSetup(),
ScriptSetup({
reactivityTransform: true,
}),
],
})
16,557 changes: 6,977 additions & 9,580 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions ref-macros.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type {
ComputedRef,
Ref,
ShallowUnwrapRef,
UnwrapRef,
WritableComputedOptions,
WritableComputedRef,
} from '@vue/composition-api'

declare const RefMarker: unique symbol
type RefValue<T> = T & { [RefMarker]?: any }

declare const ComputedRefMarker: unique symbol
type ComputedRefValue<T> = T & { [ComputedRefMarker]?: any }

declare const WritableComputedRefMarker: unique symbol
type WritableComputedRefValue<T> = T & { [WritableComputedRefMarker]?: any }

type ToRawRefs<T extends object> = {
[K in keyof T]: T[K] extends ComputedRefValue<infer V>
? ComputedRefValue<V>
: T[K] extends WritableComputedRefValue<infer V>
? WritableComputedRef<V>
: T[K] extends RefValue<infer V>
? Ref<V>
: T[K] extends object
? T[K] extends
| Function
| Map<any, any>
| Set<any>
| WeakMap<any, any>
| WeakSet<any>
? T[K]
: ToRawRefs<T[K]>
: T[K];
}

/**
* Vue ref transform macro for binding refs as reactive variables.
*/
declare function _$<T>(arg: ComputedRef<T>): ComputedRefValue<T>
declare function _$<T>(
arg: WritableComputedRef<T>
): WritableComputedRefValue<T>
declare function _$<T>(arg: Ref<T>): RefValue<T>
declare function _$<T extends object>(arg?: T): ShallowUnwrapRef<T>

/**
* Vue ref transform macro for accessing underlying refs of reactive varaibles.
*/
declare function _$$<T>(value: T): ComputedRef<T>
declare function _$$<T>(
value: WritableComputedRefValue<T>
): WritableComputedRef<T>
declare function _$$<T>(value: RefValue<T>): Ref<T>
declare function _$$<T extends object>(arg: T): ToRawRefs<T>

declare function _$ref<T>(arg?: T | Ref<T>): RefValue<UnwrapRef<T>>

declare function _$shallowRef<T>(arg?: T): RefValue<T>

declare function _$computed<T>(
getter: () => T,
// debuggerOptions?: DebuggerOptions
): ComputedRefValue<T>
declare function _$computed<T>(
options: WritableComputedOptions<T>,
// debuggerOptions?: DebuggerOptions
): WritableComputedRefValue<T>

declare global {
const $: typeof _$
const $$: typeof _$$
const $ref: typeof _$ref
const $shallowRef: typeof _$shallowRef
const $computed: typeof _$computed
}
89 changes: 89 additions & 0 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// @ts-check
import * as fs from 'node:fs'
import ts from 'rollup-plugin-esbuild'
import dts from 'rollup-plugin-dts'
import resolve from '@rollup/plugin-node-resolve'
import commonjs from '@rollup/plugin-commonjs'
import json from '@rollup/plugin-json'
import alias from '@rollup/plugin-alias'

/** @type {import('./package.json')} */
const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf-8'))

const entries = {
index: 'src/index.ts',
webpack: 'src/webpack.ts',
vite: 'src/vite.ts',
rollup: 'src/rollup.ts',
esbuild: 'src/esbuild.ts',
nuxt: 'src/nuxt.ts',
types: 'src/types.ts',
}

const external = [
...Object.keys(pkg.dependencies),
...Object.keys(pkg.peerDependencies),
'esbuild',
'rollup',
'vite',
'webpack',
'@nuxt/kit',
]


/** @type {import('rollup').RollupOptions[]} */
export default [
{
input: entries,
external,
plugins: [
alias({
entries: [
{ find: /^node:(.+)$/, replacement: '$1' },
],
}),
resolve({
preferBuiltins: true,
}),
json(),
commonjs(),
ts(),
],
onwarn({ code, message }) {
if(code === 'EMPTY_BUNDLE') return
console.error(message)
},
output:[
{
dir: 'dist',
format: 'esm',
sourcemap: 'inline',
entryFileNames: "[name].mjs",
},
{
dir: 'dist',
format: 'cjs',
exports: 'named',
sourcemap: 'inline',
entryFileNames: "[name].js",
},
]
},
{
input: entries,
external,
plugins: [
dts({ respectExternal: true }),
],
output: [
{
dir: 'dist',
entryFileNames: "[name].d.mts",
},
{
dir: 'dist',
entryFileNames: "[name].d.ts",
},
],
},
]
1 change: 1 addition & 0 deletions rollup.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './dist/rollup'
23 changes: 23 additions & 0 deletions scripts/postbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { basename, resolve } from 'node:path'
import { promises as fs } from 'node:fs'
import fg from 'fast-glob'

async function run() {
// fix cjs exports
const files = await fg('*.js', {
ignore: ['chunk-*'],
absolute: true,
cwd: resolve(__dirname, '../dist'),
})
for (const file of files) {
console.log('[postbuild]', basename(file))
const name = basename(file, '.js')
let code = await fs.readFile(file, 'utf8')
code = code.replace('exports.default =', 'module.exports =')
code += 'exports.default = module.exports;'
await fs.writeFile(file, code)
await fs.writeFile(`${name}.d.ts`, `import './shims'\nexport { default } from './dist/${name}'\n`)
}
}

run()
6 changes: 6 additions & 0 deletions shims.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// workaround for Volar to infer the ref type in <template>
// https://github.com/johnsoncodehk/volar/issues/404
declare module '@vue/runtime-dom' {
export * from '@vue/runtime-dom/dist/runtime-dom'
export { defineComponent, PropType, ObjectDirective, FunctionDirective } from '@vue/composition-api'
}
9 changes: 9 additions & 0 deletions src/core/babel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import * as babel from '@babel/core'
import { parse, parseExpression } from '@babel/parser'
import g from '@babel/generator'
import * as babel_traverse from '@babel/traverse'

export const t: typeof babel['types'] = ((babel as any).default || babel).types
export const generate: typeof g = ((g as any).default || g)
export const traverse = ((babel_traverse as any)?.default?.default as null) ?? babel_traverse?.default ?? babel_traverse
export { parseExpression, parse }
132 changes: 132 additions & 0 deletions src/core/identifiers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import type {
Expression,
File,
PrivateName,
SpreadElement,
Statement,
TSType,
} from '@babel/types'
import type { ParseResult } from '@babel/parser'
import { t, traverse } from './babel'

export function getIdentifierDeclarations(nodes: Statement[]) {
let result!: Set<string>
let programScopeUid: number
traverse(t.file(t.program(nodes)), {
Program(path) {
result = new Set(Object.keys(path.scope.bindings))
programScopeUid = (path.scope as any).uid
},
// FIXME: babel bug, temporary add TSEnumDeclaration and TSModuleDeclaration logic
TSEnumDeclaration(path) {
if ((path.scope as any).uid === programScopeUid)
result.add(path.node.id.name)
},
TSModuleDeclaration(path) {
if ((path.scope as any).uid === programScopeUid) {
const id = path.node.id
if (id.type === 'Identifier')
result.add(id.name)
}
},
})
return Array.from(result)
}

/**
* @deprecated use `getFileGlobals` instead
*/
export function getIdentifierUsages(node?: Expression | TSType | SpreadElement | PrivateName | Statement | null, identifiers = new Set<string>()) {
if (!node)
return identifiers

if (node.type === 'BlockStatement') {
node.body.forEach(child => getIdentifierUsages(child, identifiers))
}
else if (node.type === 'ExpressionStatement') {
getIdentifierUsages(node.expression, identifiers)
}
else if (node.type === 'Identifier') {
identifiers.add(node.name)
}
else if (node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression') {
getIdentifierUsages(node.object, identifiers)
if (node.computed)
getIdentifierUsages(node.property, identifiers)
}
else if (node.type === 'CallExpression' || node.type === 'OptionalCallExpression') {
getIdentifierUsages(node.callee as Expression, identifiers)
node.arguments.forEach(arg => getIdentifierUsages(arg as Expression, identifiers))
}
else if (node.type === 'BinaryExpression' || node.type === 'LogicalExpression') {
getIdentifierUsages(node.left, identifiers)
getIdentifierUsages(node.right, identifiers)
}
else if (node.type === 'UnaryExpression') {
getIdentifierUsages(node.argument, identifiers)
}
else if (node.type === 'ForOfStatement' || node.type === 'ForInStatement') {
getIdentifierUsages(node.right, identifiers)
}
else if (node.type === 'ConditionalExpression') {
getIdentifierUsages(node.test, identifiers)
getIdentifierUsages(node.consequent, identifiers)
getIdentifierUsages(node.alternate, identifiers)
}
else if (node.type === 'ObjectExpression') {
node.properties.forEach((prop) => {
if (prop.type === 'ObjectProperty') {
if (prop.computed)
getIdentifierUsages(prop.key, identifiers)
getIdentifierUsages(prop.value as Expression, identifiers)
}
else if (prop.type === 'SpreadElement') {
getIdentifierUsages(prop, identifiers)
}
})
}
else if (node.type === 'ArrayExpression') {
node.elements.forEach(element => getIdentifierUsages(element, identifiers))
}
else if (node.type === 'SpreadElement' || node.type === 'ReturnStatement') {
getIdentifierUsages(node.argument, identifiers)
}
else if (node.type === 'NewExpression') {
getIdentifierUsages(node.callee as Expression, identifiers)
node.arguments.forEach(arg => getIdentifierUsages(arg as Expression, identifiers))
}
else if (node.type === 'ArrowFunctionExpression' || node.type === 'FunctionDeclaration' || node.type === 'FunctionExpression') {
getIdentifierUsages(node.body, identifiers)
}
else if (node.type === 'TemplateLiteral') {
node.expressions.forEach(expr => getIdentifierUsages(expr, identifiers))
}
// else {
// console.log(node)
// }
return identifiers
}

export function getFileGlobals(result: ParseResult<File>) {
let globals!: Set<string>
let programScopeUid: number
traverse(result, {
Program(path) {
globals = new Set(Object.keys((path.scope as any).globals))
programScopeUid = (path.scope as any).uid
},
// FIXME: babel bug, temporary add TSEnumDeclaration and TSModuleDeclaration logic
TSEnumDeclaration(path) {
if ((path.scope as any).uid === programScopeUid)
globals.delete(path.node.id.name)
},
TSModuleDeclaration(path) {
if ((path.scope as any).uid === programScopeUid) {
const id = path.node.id
if (id.type === 'Identifier')
globals.delete(id.name)
}
},
})
return Array.from(globals)
}
3 changes: 3 additions & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './transform'
export * from './transformScriptSetup'
export * from '../types'
94 changes: 71 additions & 23 deletions src/macros.ts → src/core/macros.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
// modified from https://github.com/vuejs/vue-next/blob/main/packages/compiler-sfc/src/compileScript.ts

import {
import type {
CallExpression,
Node,
ObjectExpression,
TSType,
TSTypeLiteral,
TSFunctionType,
ObjectProperty,
Statement,
CallExpression,
TSFunctionType,
TSInterfaceBody,
TSType,
TSTypeLiteral,
} from '@babel/types'
import { types as t } from '@babel/core'
import { parseExpression } from '@babel/parser'
import { PropTypeData } from './types'
import { parseExpression, t } from './babel'

// Special compiler macros
const DEFINE_PROPS = 'defineProps'
const DEFINE_EMITS = 'defineEmits'
const DEFINE_EXPOSE = 'defineExpose'
const WITH_DEFAULTS = 'withDefaults'
const DEFINE_SLOTS = 'defineSlots'

export interface PropTypeData {
key: string
type: string[] | string
required: boolean
}

export function applyMacros(nodes: Statement[]) {
let hasDefinePropsCall = false
let hasDefineEmitCall = false
let hasDefineSlotsCall = false
let propsRuntimeDecl: Node | undefined
let propsRuntimeDefaults: Node | undefined
let propsTypeDecl: TSTypeLiteral | TSInterfaceBody | undefined
@@ -35,6 +41,7 @@ export function applyMacros(nodes: Statement[]) {
| TSInterfaceBody
| undefined
let emitsTypeDeclRaw: Node | undefined
let exposeDecl: CallExpression['arguments'][number] | undefined

// props/emits declared via types
const typeDeclaredProps: Record<string, PropTypeData> = {}
@@ -43,8 +50,8 @@ export function applyMacros(nodes: Statement[]) {

function error(
msg: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
node: Node,

_node: Node,
): never {
throw new Error(msg)
}
@@ -185,9 +192,35 @@ export function applyMacros(nodes: Statement[]) {
}

function processDefineExpose(node: Node): boolean {
if (isCallOf(node, DEFINE_EXPOSE))
error(`Vue 2 does not support ${DEFINE_EXPOSE}()`, node)
return false
if (!isCallOf(node, DEFINE_EXPOSE))
return false

if (exposeDecl)
error(`duplicate ${DEFINE_EXPOSE}() call`, node)

if (node.arguments.length !== 1)
error(`${DEFINE_EXPOSE}() requires one argument`, node)

exposeDecl = node.arguments[0]

return true
}

function processDefineSlots(
node: Node,
): boolean {
if (!isCallOf(node, DEFINE_SLOTS))
return false

if (hasDefineSlotsCall)
error(`duplicate ${DEFINE_SLOTS}() call`, node)

hasDefineSlotsCall = true

if (node.arguments.length > 0)
error(`${DEFINE_SLOTS}() cannot accept arguments`, node)

return true
}

function genRuntimeProps(props: Record<string, PropTypeData>) {
@@ -213,10 +246,9 @@ export function applyMacros(nodes: Statement[]) {
if (prop)
value.required = false

const entries = Object.entries(value).map(([key, value]) =>
key === 'type'
? t.objectProperty(t.identifier(key), t.arrayExpression(value.map((i: any) => t.identifier(i))) as any)
: t.objectProperty(t.identifier(key), parseExpression(JSON.stringify(value)) as any),
const entries = Object.entries(value).map(([key, value]) => key === 'type'
? t.objectProperty(t.identifier(key), typeof value === 'string' ? t.identifier(value) : t.arrayExpression(value.map((i: any) => t.identifier(i))) as any)
: t.objectProperty(t.identifier(key), parseExpression(JSON.stringify(value)) as any),
)

if (prop)
@@ -240,31 +272,47 @@ export function applyMacros(nodes: Statement[]) {
}
}

function throwIfAwait(node: Node) {
if (node.type === 'AwaitExpression')
error('top-level await is not supported in Vue 2', node)
}

nodes = nodes
.map((node) => {
.map((raw: Node) => {
let node = raw
if (raw.type === 'ExpressionStatement')
node = raw.expression

if (node.type === 'VariableDeclaration' && !node.declare) {
const total = node.declarations.length
for (let i = 0; i < total; i++) {
const decl = node.declarations[i]
if (decl.init) {
if (processDefineEmits(decl.init))
decl.init = t.memberExpression(t.identifier('__ctx'), t.identifier('emit')) as any
decl.init = t.memberExpression(t.identifier('__ctx'), t.identifier('emit'))
else if (processDefineSlots(decl.init))
decl.init = t.memberExpression(t.identifier('__ctx'), t.identifier('slots'))
else if (processDefineProps(decl.init) || processWithDefaults(decl.init))
decl.init = t.identifier('__props') as any
else
throwIfAwait(decl.init)
}
}
}

if (processDefineEmits(node) || processDefineProps(node) || processDefineExpose(node))
if (processWithDefaults(node) || processDefineEmits(node) || processDefineProps(node) || processDefineExpose(node) || processDefineSlots(node))
return null

return node
throwIfAwait(node)

return raw
})
.filter(Boolean) as Statement[]

return {
nodes,
props: getProps(),
expose: exposeDecl,
}
}

@@ -293,7 +341,7 @@ function extractRuntimeProps(
(m.type === 'TSPropertySignature' || m.type === 'TSMethodSignature')
&& m.key.type === 'Identifier'
) {
let type
let type: string[] | undefined
if (m.type === 'TSMethodSignature') {
type = ['Function']
}
@@ -306,7 +354,7 @@ function extractRuntimeProps(
props[m.key.name] = {
key: m.key.name,
required: !m.optional,
type: type || ['null'],
type: type?.length === 1 ? type[0] : type || 'null',
}
}
}
14 changes: 14 additions & 0 deletions src/core/options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import type { ResolvedOptions, ScriptSetupTransformOptions } from '../types'

export function resolveOptions(options: ScriptSetupTransformOptions = {}): ResolvedOptions {
return Object.assign(
{},
{
sourceMap: true,
reactivityTransform: false,
importHelpersFrom: '@vue/composition-api',
astTransforms: {},
},
options,
)
}
402 changes: 402 additions & 0 deletions src/core/parseSFC.ts

Large diffs are not rendered by default.

82 changes: 82 additions & 0 deletions src/core/transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import MagicString from 'magic-string'
import { shouldTransform as shouldTransformRefSugar, transform as transformRef } from '@vue/reactivity-transform'
import type { ResolvedOptions, ScriptSetupTransformOptions, TransformResult } from '../types'
import { parseSFC } from './parseSFC'
import { transformScriptSetup } from './transformScriptSetup'
import { transformSfcRefSugar } from './transformSfcRefSugar'
import { resolveOptions } from './options'

export const scriptSetupRE = /<script\s+(.*\s+)?setup(\s+.*)?\s*>/

export function shouldTransform(code: string, id: string, options?: ScriptSetupTransformOptions): boolean {
// avoid transforming twice
if (code.includes('export default __sfc_main'))
return false
return (options?.reactivityTransform && shouldTransformRefSugar(code)) || scriptSetupRE.test(code)
}

export async function transform(input: string, id: string, options?: ScriptSetupTransformOptions): Promise<TransformResult> {
if (!shouldTransform(input, id, options))
return null
const resolved = resolveOptions(options)
if (id.endsWith('.vue') || id.includes('.vue?vue'))
return await transformVue(input, id, resolved)
else
return transformNonVue(input, id, resolved)
}

function transformNonVue(input: string, id: string, options: ResolvedOptions): TransformResult {
if (options.reactivityTransform && shouldTransformRefSugar(input)) {
return transformRef(input, {
filename: id,
sourceMap: options.sourceMap,
importHelpersFrom: options.importHelpersFrom,
}) as any
}
return null
}

async function transformVue(input: string, id: string, options: ResolvedOptions): Promise<TransformResult> {
const s = new MagicString(input)

const sfc = await parseSFC(input, id)

if (options.reactivityTransform)
transformSfcRefSugar(sfc, options)

const { code } = transformScriptSetup(sfc, options)

const attributes = {
...sfc.script.attrs,
...sfc.scriptSetup.attrs,
}
delete attributes.setup
const attr = Object.entries(attributes)
.map(([key, value]) => value ? `${key}="${value}"` : key)
.join(' ')

if (code) {
const block = `<script ${attr}>\n${code}\n</script>`

s.remove(sfc.script.start, sfc.script.end)
if (sfc.scriptSetup.start !== sfc.scriptSetup.end) {
s.overwrite(
sfc.scriptSetup.start,
sfc.scriptSetup.end,
block,
)
}
else {
s.prependLeft(0, `${block}\n`)
}
}
return {
code: s.toString(),
map: options.sourceMap
? s.generateMap({
source: id,
includeContent: true,
}) as any
: null,
}
}
235 changes: 235 additions & 0 deletions src/core/transformScriptSetup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
import { capitalize } from '@vue/shared'
import type { Node, ObjectExpression, Statement } from '@babel/types'
import { notNullish, partition, uniq } from '@antfu/utils'
import { parserOptions } from '@vue/compiler-dom'
import type { ParsedSFC, ScriptSetupTransformOptions } from '../types'
import { applyMacros } from './macros'
import { getIdentifierDeclarations } from './identifiers'
import { generate, t } from './babel'
import { pascalize } from './utils'

function isAsyncImport(node: Statement) {
if (t.isVariableDeclaration(node)) {
const declaration = node.declarations[0]

return (
declaration !== undefined
&& t.isCallExpression(declaration.init)
&& t.isIdentifier(declaration.init.callee)
&& declaration.init.callee.name === 'defineAsyncComponent'
)
}

return false
}

export function transformScriptSetup(
sfc: ParsedSFC,
options?: ScriptSetupTransformOptions,
) {
const { scriptSetup, script, template } = sfc

const { nodes: body, props, expose } = applyMacros(scriptSetup.ast.body)

const [hoisted, setupBody] = partition(
body,
n =>
isAsyncImport(n)
|| t.isImportDeclaration(n)
|| t.isExportNamedDeclaration(n)
|| n.type.startsWith('TS'),
)

// get all identifiers in `<script setup>` and `<script>`
const declarationArray = uniq([
...getIdentifierDeclarations(hoisted),
...getIdentifierDeclarations(setupBody),
...getIdentifierDeclarations(script.ast.body),
]).filter(notNullish)

// filter out identifiers that are used in `<template>`
const returns: ObjectExpression['properties'] = declarationArray
.filter(i => template.identifiers.has(i))
.map((i) => {
const id = t.identifier(i)
return t.objectProperty(id, id, false, true)
})

const nonNativeTags = new Set(
Array.from(template.tags)
.filter(tag => !parserOptions.isNativeTag!(tag))
.map(pascalize),
)

const components = Array.from(nonNativeTags)
.map(
component =>
declarationArray.find(declare => declare === component)
?? declarationArray.find(declare => pascalize(declare) === component),
)
.filter(notNullish)

const directiveDeclaration = Array.from(template.directives)
.map((directive) => {
const identifier = declarationArray.find(
declaration => declaration === `v${capitalize(directive)}`,
)
if (identifier === undefined)
return undefined

return { identifier, directive }
})
.filter(notNullish)

// append `<script setup>` imports to `<script>`

const __sfc = t.identifier('__sfc_main')

let hasBody = false

const bodyNodes = script.ast.body.map((node: Node) => {
// replace `export default` with a temproray variable
// `const __sfc_main = { ... }`
if (node.type === 'ExportDefaultDeclaration') {
hasBody = true
return t.variableDeclaration('const', [
t.variableDeclarator(__sfc, node.declaration as any),
])
}
return node
})

let ast = t.program([
...sfc.extraDeclarations,
...hoisted,
...bodyNodes,
] as Statement[])

// inject `const __sfc_main = {}` if `<script>` has default export
if (!hasBody) {
ast.body.push(
t.variableDeclaration('const', [
t.variableDeclarator(__sfc, t.objectExpression([])),
]),
)
}

// inject props function
// `__sfc_main.props = { ... }`
if (props) {
hasBody = true
ast.body.push(
t.expressionStatement(
t.assignmentExpression(
'=',
t.memberExpression(__sfc, t.identifier('props')),
props as any,
),
) as any,
)
}

// inject setup function
// `__sfc_main.setup = () => {}`
if (body.length) {
hasBody = true
const returnExpr = expose
? t.callExpression(
t.memberExpression(t.identifier('Object'), t.identifier('assign')),
[t.objectExpression(returns), expose],
)
: t.objectExpression(returns)
const returnStatement = t.returnStatement(returnExpr)

ast.body.push(
t.expressionStatement(
t.assignmentExpression(
'=',
t.memberExpression(__sfc, t.identifier('setup')),
t.arrowFunctionExpression(
[t.identifier('__props'), t.identifier('__ctx')],
t.blockStatement([...setupBody, returnStatement as any]),
),
),
) as any,
)
}

// inject components
// `__sfc_main.components = Object.assign({ ... }, __sfc_main.components)`
if (components.length) {
hasBody = true
const componentsObject = t.objectExpression(
components.map((i) => {
const id = t.identifier(i)
return t.objectProperty(id, id, false, true)
}),
)

ast.body.push(
t.expressionStatement(
t.assignmentExpression(
'=',
t.memberExpression(__sfc, t.identifier('components')),
t.callExpression(
t.memberExpression(t.identifier('Object'), t.identifier('assign')),
[
componentsObject,
t.memberExpression(__sfc, t.identifier('components')),
],
),
),
) as any,
)
}

// inject directives
// `__sfc_main.directives = Object.assign({ ... }, __sfc_main.directives)`
if (directiveDeclaration.length) {
hasBody = true
const directivesObject = t.objectExpression(
directiveDeclaration.map(({ directive, identifier }) =>
t.objectProperty(
t.identifier(directive),
t.identifier(identifier),
false,
false,
),
),
)

ast.body.push(
t.expressionStatement(
t.assignmentExpression(
'=',
t.memberExpression(__sfc, t.identifier('directives')),
t.callExpression(
t.memberExpression(t.identifier('Object'), t.identifier('assign')),
[
directivesObject,
t.memberExpression(__sfc, t.identifier('directives')),
],
),
),
) as any,
)
}

if (!hasBody && !options?.astTransforms) {
return {
ast: null,
code: '',
}
}

// re-export
// `export default __sfc_main`
ast.body.push(t.exportDefaultDeclaration(__sfc) as any)

ast = options?.astTransforms?.post?.(ast, sfc) || ast

return {
ast,
code: generate(ast).code,
}
}
27 changes: 27 additions & 0 deletions src/core/transformSfcRefSugar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { shouldTransform, transformAST } from '@vue/reactivity-transform'
import MagicString from 'magic-string'
import type { ParsedSFC, ResolvedOptions } from '../types'
import { parse, t } from './babel'

export function transformSfcRefSugar(sfc: ParsedSFC, options: ResolvedOptions) {
const importedHelpers = new Set<string>()

for (const script of [sfc.script, sfc.scriptSetup]) {
if (shouldTransform(script.content)) {
const s = new MagicString(script.content)
const { importedHelpers: imports } = transformAST(script.ast, s)
Array.from(imports).forEach(helper => importedHelpers.add(helper))
script.content = s.toString()
script.ast = parse(script.content, sfc.parserOptions).program
}
}

if (importedHelpers.size) {
sfc.extraDeclarations = [
t.importDeclaration(
Array.from(importedHelpers).map(i => t.importSpecifier(t.identifier(`_${i}`), t.identifier(i))),
t.stringLiteral(options.importHelpersFrom),
),
]
}
}
9 changes: 9 additions & 0 deletions src/core/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { camelize, capitalize } from '@vue/shared'

export const pascalize = (str: string) => capitalize(camelize(str))

export const isNotNil = <T>(value: T): value is NonNullable<T> => value != null

export function exhaustiveCheckReturnUndefined(_param: never) {
return undefined as never
}
3 changes: 3 additions & 0 deletions src/esbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import unplugin from '.'

export default unplugin.esbuild
32 changes: 31 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
export * from './transform'
import { createUnplugin } from 'unplugin'
import { createFilter } from '@rollup/pluginutils'
import type { PluginOptions } from './types'
import { transform } from './core'

export * from './core'

export const unplugin = createUnplugin<PluginOptions>((options = {}) => {
const filter = createFilter(
options.include || (options.reactivityTransform ? [/\.vue$/, /\.vue\?vue/, /\.[jt]sx?$/] : [/\.vue$/, /\.vue\?vue/]),
options.exclude || [/node_modules/, /\.git/, /\.nuxt/],
)

return {
name: 'unplugin-vue2-script-setup',
enforce: 'pre',
transformInclude(id) {
return filter(id)
},
async transform(code, id) {
try {
return await transform(code, id, options)
}
catch (e: any) {
this.error(e)
}
},
}
})

export default unplugin
1 change: 1 addition & 0 deletions src/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './core'
17 changes: 11 additions & 6 deletions src/nuxt.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
import vitePlugin from './vite-plugin'
import webpackPlugin from './webpack-plugin'
import defu from 'defu'
import type { PluginOptions } from './types'
import unplugin from '.'

function scriptSetupModule(this: any, inlineOptions: PluginOptions = {}) {
const options = defu(inlineOptions, this.nuxt.options.scriptSetup)

export default function(this: any) {
// install webpack plugin
this.extendBuild((config: any) => {
config.plugins = config.plugins || []
config.plugins.unshift(webpackPlugin())
config.plugins.unshift(unplugin.webpack(options))
})

// install vite plugin
this.nuxt.hook('vite:extend', async(vite: any) => {
this.nuxt.hook('vite:extend', async (vite: any) => {
vite.config.plugins = vite.config.plugins || []
vite.config.plugins.push(vitePlugin())
vite.config.plugins.push(unplugin.vite(options))
})
}

export default scriptSetupModule
126 changes: 0 additions & 126 deletions src/parse.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/rollup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import unplugin from '.'

export default unplugin.rollup
30 changes: 0 additions & 30 deletions src/transform.ts

This file was deleted.

152 changes: 0 additions & 152 deletions src/transformScriptSetup.ts

This file was deleted.

55 changes: 47 additions & 8 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,64 @@
export interface TagMeta {
import type { ParserOptions } from '@babel/parser'
import type { Node, Program } from '@babel/types'
import type { FilterPattern } from '@rollup/pluginutils'

export interface ScriptTagMeta {
start: number
end: number
contentStart: number
contentEnd: number
content: string
attrs: Record<string, string>
found: boolean
ast: Program
}

export interface ParseResult {
export interface ParsedSFC {
id?: string
template: {
/** foo-bar -> FooBar */
components: Set<string>
tags: Set<string>
/** v-foo-bar -> fooBar */
directives: Set<string>
identifiers: Set<string>
}
scriptSetup: TagMeta
script: TagMeta
scriptSetup: ScriptTagMeta
script: ScriptTagMeta
parserOptions: ParserOptions
extraDeclarations: Node[]
}

export interface ScriptSetupTransformOptions {
astTransforms?: {
script?: (ast: Program) => Program
scriptSetup?: (ast: Program) => Program
post?: (ast: Program, sfc: ParsedSFC) => Program
}
reactivityTransform?: boolean
importHelpersFrom?: string
sourceMap?: boolean
}

export interface PropTypeData {
key: string
type: string[]
required: boolean
export interface PluginOptions extends ScriptSetupTransformOptions {
include?: FilterPattern
exclude?: FilterPattern
}

export type ResolvedOptions = Required<ScriptSetupTransformOptions>

export interface SourceMap {
file: string
mappings: string
names: string[]
sources: string[]
sourcesContent: string[]
version: number
toString(): string
toUrl(): string
}

export type TransformResult = {
code: string
readonly map: SourceMap | null
} | null
15 changes: 0 additions & 15 deletions src/vite-plugin.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/vite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import unplugin from '.'

export default unplugin.vite
16 changes: 0 additions & 16 deletions src/webpack-plugin.ts

This file was deleted.

3 changes: 3 additions & 0 deletions src/webpack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import unplugin from '.'

export default unplugin.webpack
Loading