chore(sfc-playground): enable ref transform

This commit is contained in:
Evan You 2021-08-23 12:21:17 -04:00
parent 6453359852
commit 80ed275073
6 changed files with 91 additions and 115 deletions

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import { downloadProject } from './download/download'
import { setVersion, resetVersion } from './sfcCompiler'
import { setVersion, resetVersion } from './transform'
import { ref, onMounted } from 'vue'
const currentCommit = __COMMIT__
@ -44,8 +44,8 @@ async function fetchVersions(): Promise<string[]> {
`https://api.github.com/repos/vuejs/vue-next/releases?per_page=100`
)
const releases: any[] = await res.json()
const versions = releases.map(
r => (/^v/.test(r.tag_name) ? r.tag_name.substr(1) : r.tag_name)
const versions = releases.map(r =>
/^v/.test(r.tag_name) ? r.tag_name.substr(1) : r.tag_name
)
const minVersion = versions.findIndex(v => v === '3.0.10')
return versions.slice(0, minVersion + 1)
@ -55,7 +55,7 @@ async function fetchVersions(): Promise<string[]> {
<template>
<nav>
<h1>
<img alt="logo" src="/logo.svg">
<img alt="logo" src="/logo.svg" />
<span>Vue SFC Playground</span>
</h1>
<div class="links">
@ -68,31 +68,61 @@ async function fetchVersions(): Promise<string[]> {
<li v-for="version of publishedVersions">
<a @click="setVueVersion(version)">v{{ version }}</a>
</li>
<li><a @click="resetVueVersion">This Commit ({{ currentCommit }})</a></li>
<li>
<a href="https://app.netlify.com/sites/vue-sfc-playground/deploys" target="_blank">Commits History</a>
<a @click="resetVueVersion">This Commit ({{ currentCommit }})</a>
</li>
<li>
<a
href="https://app.netlify.com/sites/vue-sfc-playground/deploys"
target="_blank"
>Commits History</a
>
</li>
</ul>
</div>
<button class="share" @click="copyLink">
<svg width="1.4em" height="1.4em" viewBox="0 0 24 24">
<g fill="none" stroke="#626262" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="18" cy="5" r="3"/>
<circle cx="6" cy="12" r="3"/>
<circle cx="18" cy="19" r="3"/>
<path d="M8.59 13.51l6.83 3.98"/>
<path d="M15.41 6.51l-6.82 3.98"/>
<g
fill="none"
stroke="#626262"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="18" cy="5" r="3" />
<circle cx="6" cy="12" r="3" />
<circle cx="18" cy="19" r="3" />
<path d="M8.59 13.51l6.83 3.98" />
<path d="M15.41 6.51l-6.82 3.98" />
</g>
</svg>
</button>
</button>
<button class="download" @click="downloadProject">
<svg width="1.7em" height="1.7em" viewBox="0 0 24 24">
<g fill="#626262">
<rect x="4" y="18" width="16" height="2" rx="1" ry="1"/>
<rect x="3" y="17" width="4" height="2" rx="1" ry="1" transform="rotate(-90 5 18)"/>
<rect x="17" y="17" width="4" height="2" rx="1" ry="1" transform="rotate(-90 19 18)"/>
<path d="M12 15a1 1 0 0 1-.58-.18l-4-2.82a1 1 0 0 1-.24-1.39a1 1 0 0 1 1.4-.24L12 12.76l3.4-2.56a1 1 0 0 1 1.2 1.6l-4 3a1 1 0 0 1-.6.2z"/>
<path d="M12 13a1 1 0 0 1-1-1V4a1 1 0 0 1 2 0v8a1 1 0 0 1-1 1z"/>
<rect x="4" y="18" width="16" height="2" rx="1" ry="1" />
<rect
x="3"
y="17"
width="4"
height="2"
rx="1"
ry="1"
transform="rotate(-90 5 18)"
/>
<rect
x="17"
y="17"
width="4"
height="2"
rx="1"
ry="1"
transform="rotate(-90 19 18)"
/>
<path
d="M12 15a1 1 0 0 1-.58-.18l-4-2.82a1 1 0 0 1-.24-1.39a1 1 0 0 1 1.4-.24L12 12.76l3.4-2.56a1 1 0 0 1 1.2 1.6l-4 3a1 1 0 0 1-.6.2z"
/>
<path d="M12 13a1 1 0 0 1-1-1V4a1 1 0 0 1 2 0v8a1 1 0 0 1-1 1z" />
</g>
</svg>
</button>

View File

@ -20,13 +20,9 @@ function focus({ el }: VNode) {
function doneAddFile() {
const filename = pendingFilename.value
if (
!filename.endsWith('.vue') &&
!filename.endsWith('.js') &&
filename !== 'import-map.json'
) {
if (!/\.(vue|js|ts)$/.test(filename) && filename !== 'import-map.json') {
store.errors = [
`Playground only supports *.vue, *.js files or import-map.json.`
`Playground only supports *.vue, *.js, *.ts files or import-map.json.`
]
return
}

View File

@ -10,7 +10,7 @@ import {
} from 'vue'
import srcdoc from './srcdoc.html?raw'
import { PreviewProxy } from './PreviewProxy'
import { MAIN_FILE, vueRuntimeUrl } from '../sfcCompiler'
import { MAIN_FILE, vueRuntimeUrl } from '../transform'
import { compileModulesForPreview } from './moduleCompiler'
import { store } from '../store'

View File

@ -1,13 +1,14 @@
import { store, File } from '../store'
import { MAIN_FILE } from '../sfcCompiler'
import { MAIN_FILE } from '../transform'
import { babelParse, MagicString, walk } from '@vue/compiler-sfc'
import {
babelParse,
MagicString,
walk,
walkIdentifiers
} from '@vue/compiler-sfc'
walkIdentifiers,
extractIdentifiers,
isInDestructureAssignment,
isStaticProperty
} from '@vue/compiler-core'
import { babelParserDefaultPlugins } from '@vue/shared'
import { ExportSpecifier, Identifier, Node, ObjectProperty } from '@babel/types'
import { ExportSpecifier, Identifier, Node } from '@babel/types'
export function compileModulesForPreview() {
return processFile(store.files[MAIN_FILE]).reverse()
@ -110,9 +111,8 @@ function processFile(file: File, seen = new Set<File>()) {
} else if (node.declaration.type === 'VariableDeclaration') {
// export const foo = 1, bar = 2
for (const decl of node.declaration.declarations) {
const names = extractNames(decl.id as any)
for (const name of names) {
defineExport(name)
for (const id of extractIdentifiers(decl.id)) {
defineExport(id.name)
}
}
}
@ -231,73 +231,3 @@ function processFile(file: File, seen = new Set<File>()) {
// return a list of files to further process
return processed
}
const isStaticProperty = (node: Node): node is ObjectProperty =>
node.type === 'ObjectProperty' && !node.computed
function extractNames(param: Node): string[] {
return extractIdentifiers(param).map(id => id.name)
}
function extractIdentifiers(
param: Node,
nodes: Identifier[] = []
): Identifier[] {
switch (param.type) {
case 'Identifier':
nodes.push(param)
break
case 'MemberExpression':
let object: any = param
while (object.type === 'MemberExpression') {
object = object.object
}
nodes.push(object)
break
case 'ObjectPattern':
param.properties.forEach(prop => {
if (prop.type === 'RestElement') {
extractIdentifiers(prop.argument, nodes)
} else {
extractIdentifiers(prop.value, nodes)
}
})
break
case 'ArrayPattern':
param.elements.forEach(element => {
if (element) extractIdentifiers(element, nodes)
})
break
case 'RestElement':
extractIdentifiers(param.argument, nodes)
break
case 'AssignmentPattern':
extractIdentifiers(param.left, nodes)
break
}
return nodes
}
function isInDestructureAssignment(parent: Node, parentStack: Node[]): boolean {
if (
parent &&
(parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')
) {
let i = parentStack.length
while (i--) {
const p = parentStack[i]
if (p.type === 'AssignmentExpression') {
return true
} else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {
break
}
}
}
return false
}

View File

@ -1,15 +1,18 @@
import { reactive, watchEffect } from 'vue'
import { compileFile, MAIN_FILE } from './sfcCompiler'
import { compileFile, MAIN_FILE } from './transform'
import { utoa, atou } from './utils'
const welcomeCode = `
<script setup>
import { ref } from 'vue'
const msg = ref('Hello World!')
</script>
<template>
<h1>{{ msg }}</h1>
<input v-model="msg">
</template>
<script setup>
const msg = 'Hello World!'
</script>
`.trim()
export class File {

View File

@ -1,5 +1,10 @@
import { store, File } from './store'
import { SFCDescriptor, BindingMetadata } from '@vue/compiler-sfc'
import {
SFCDescriptor,
BindingMetadata,
shouldTransformRef,
transformRef
} from '@vue/compiler-sfc'
import * as defaultCompiler from '@vue/compiler-sfc'
import { ref } from 'vue'
@ -36,6 +41,12 @@ export function resetVersion() {
vueRuntimeUrl.value = defaultVueUrl
}
async function transformTS(src: string) {
return (await import('sucrase')).transform(src, {
transforms: ['typescript']
}).code
}
export async function compileFile({ filename, code, compiled }: File) {
if (!code.trim()) {
store.errors = []
@ -43,6 +54,14 @@ export async function compileFile({ filename, code, compiled }: File) {
}
if (!filename.endsWith('.vue')) {
if (shouldTransformRef(code)) {
code = transformRef(code, { filename }).code
}
if (filename.endsWith('.ts')) {
code = await transformTS(code)
}
compiled.js = compiled.ssr = code
store.errors = []
return
@ -190,7 +209,7 @@ async function doCompileScript(
try {
const compiledScript = SFCCompiler.compileScript(descriptor, {
id,
refSugar: true,
refTransform: true,
inlineTemplate: true,
templateOptions: {
ssr,
@ -210,9 +229,7 @@ async function doCompileScript(
SFCCompiler.rewriteDefault(compiledScript.content, COMP_IDENTIFIER)
if ((descriptor.script || descriptor.scriptSetup)!.lang === 'ts') {
code = (await import('sucrase')).transform(code, {
transforms: ['typescript']
}).code
code = await transformTS(code)
}
return [code, compiledScript.bindings]