Skip to content

Commit

Permalink
chore(sfc-playground): enable ref transform
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Aug 23, 2021
1 parent 6453359 commit 80ed275
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 115 deletions.
66 changes: 48 additions & 18 deletions packages/sfc-playground/src/Header.vue
Original file line number Diff line number Diff line change
@@ -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__
Expand Down Expand Up @@ -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)
Expand All @@ -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">
Expand All @@ -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>
Expand Down
8 changes: 2 additions & 6 deletions packages/sfc-playground/src/editor/FileSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
2 changes: 1 addition & 1 deletion packages/sfc-playground/src/output/Preview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
90 changes: 10 additions & 80 deletions packages/sfc-playground/src/output/moduleCompiler.ts
Original file line number Diff line number Diff line change
@@ -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()
Expand Down Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -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
}
13 changes: 8 additions & 5 deletions packages/sfc-playground/src/store.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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'

Expand Down Expand Up @@ -36,13 +41,27 @@ 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 = []
return
}

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
Expand Down Expand Up @@ -190,7 +209,7 @@ async function doCompileScript(
try {
const compiledScript = SFCCompiler.compileScript(descriptor, {
id,
refSugar: true,
refTransform: true,
inlineTemplate: true,
templateOptions: {
ssr,
Expand All @@ -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]
Expand Down

0 comments on commit 80ed275

Please sign in to comment.