setupin 3.0.0-beta.2 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -16
- package/README.zh-CN.md +98 -16
- package/dist/main.js +48 -48
- package/dist/main.prod.js +96 -99
- package/package.json +1 -3
package/README.md
CHANGED
|
@@ -10,32 +10,111 @@
|
|
|
10
10
|
<a href="https://bundlephobia.com/package/setupin"><img src="https://img.shields.io/bundlephobia/minzip/setupin"></a>
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
-
## 😏
|
|
13
|
+
## 😏 What is a setupin?
|
|
14
14
|
|
|
15
|
-
**setupin** allows you to write Vue's [\<script **setup
|
|
15
|
+
**setupin** allows you to write Vue's [\<script **setup**>](https://vuejs.org/api/sfc-script-setup.html)**in** HTML.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
> Offer a friendly environment for beginners to easily grasp the core usage of Vue.
|
|
19
|
-
2. **Simple development**
|
|
20
|
-
> Provide a convenient way to rapidly develop small webpage without complex configurations.
|
|
21
|
-
3. **Quick experience**
|
|
22
|
-
> Allow users to quickly experiment with Vue's new features in HTML and feel its charm.
|
|
17
|
+
Using the [vue/compiler-sfc](https://github.com/vuejs/core/tree/main/packages/compiler-sfc#readme), which compiled at runtime for esm vue code format, and dynamic execution.
|
|
23
18
|
|
|
24
|
-
## 🤯
|
|
19
|
+
## 🤯 Code comparison
|
|
25
20
|
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
<h4 align=center>esm.html</h4>
|
|
22
|
+
It's a little more complicated
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<!DOCTYPE html>
|
|
26
|
+
<html lang="en">
|
|
27
|
+
<head>
|
|
28
|
+
<meta charset="UTF-8">
|
|
29
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
30
|
+
<title>esm</title>
|
|
31
|
+
<style>
|
|
32
|
+
button {
|
|
33
|
+
font-size: larger;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
<div id="app">
|
|
39
|
+
<button @click="count++">{{ count }}</button>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<script type="module">
|
|
43
|
+
import { createApp, defineComponent, ref } from 'https://unpkg.com/vue/dist/vue.esm-browser.js';
|
|
44
|
+
const App = defineComponent(() => {
|
|
45
|
+
const count = ref(0);
|
|
46
|
+
return {
|
|
47
|
+
count
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
createApp(App).mount('#app')
|
|
51
|
+
</script>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
<h4 align=center>setup.vue</h4>
|
|
57
|
+
Cannot run directly in the browser
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<script setup>
|
|
61
|
+
import { ref } from 'vue'
|
|
62
|
+
const count = ref(0)
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<button @click="count++">{{ count }}</button>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
button {
|
|
71
|
+
font-size: larger;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
<h4 align=center>setupin.html</h4>
|
|
77
|
+
unit as one
|
|
30
78
|
|
|
31
|
-
|
|
79
|
+
```html
|
|
80
|
+
<head>
|
|
81
|
+
<meta charset="UTF-8">
|
|
82
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
83
|
+
<title>setupin</title>
|
|
84
|
+
<script src="https://unpkg.com/setupin"></script>
|
|
85
|
+
</head>
|
|
86
|
+
|
|
87
|
+
<script setup>
|
|
88
|
+
import { ref } from 'vue'
|
|
89
|
+
const count = ref(0)
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<template>
|
|
93
|
+
<button @click="count++">{{ count }}</button>
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
button {
|
|
98
|
+
font-size: larger;
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
101
|
+
```
|
|
32
102
|
|
|
103
|
+
It's exactly the same as [\<script setup>](https://vuejs.org/api/sfc-script-setup.html) except for the \<head>
|
|
33
104
|
## 🤓 Characteristics
|
|
34
105
|
|
|
35
|
-
- [x] supports esm import syntax
|
|
36
106
|
- [x] [top-level await](https://vuejs.org/api/sfc-script-setup.html#top-level-await)
|
|
37
107
|
- [x] [sfc css features](https://vuejs.org/api/sfc-css-features.html)
|
|
38
|
-
- [
|
|
108
|
+
- [ ] Split [component](https://vuejs.org/guide/essentials/component-basics.html)
|
|
109
|
+
|
|
110
|
+
## 🤔 Why setupin
|
|
111
|
+
|
|
112
|
+
1. **Easy to learn**
|
|
113
|
+
Offer a friendly environment for beginners to easily grasp the core usage of Vue.
|
|
114
|
+
2. **Simple development**
|
|
115
|
+
Provide a convenient way to rapidly develop small webpage without complex configurations.
|
|
116
|
+
3. **Quick experience**
|
|
117
|
+
Allow users to quickly experiment with Vue's new features in HTML and feel its charm.
|
|
39
118
|
|
|
40
119
|
## 😝 Playground
|
|
41
120
|
|
package/README.zh-CN.md
CHANGED
|
@@ -10,32 +10,114 @@
|
|
|
10
10
|
<a href="https://bundlephobia.com/package/setupin"><img src="https://img.shields.io/bundlephobia/minzip/setupin"></a>
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
|
-
## 😏
|
|
13
|
+
## 😏 setupin 是什么?
|
|
14
14
|
|
|
15
|
-
**setupin** 允许你在 HTML 中编写 Vue 的 [\<script setup
|
|
15
|
+
**setupin** 允许你在 HTML 中编写 Vue 的 [\<script setup>](https://cn.vuejs.org/api/sfc-script-setup.html)语法。
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
> 为初学者提供一个友好的环境,帮助他们轻松上手 Vue 的核心用法。
|
|
19
|
-
2. **简易开发**
|
|
20
|
-
> 提供便捷的方式,助力快速开发小网页,无需繁琐的配置。
|
|
21
|
-
3. **快速体验**
|
|
22
|
-
> 让用户可以快速在 HTML 中尝试 Vue 的新特性,感受其魅力。
|
|
17
|
+
利用[vue/compiler-sfc](https://github.com/vuejs/core/tree/main/packages/compiler-sfc#readme),在运行时编译为esm格式的vue代码,并动态执行。
|
|
23
18
|
|
|
24
|
-
## 🤯
|
|
19
|
+
## 🤯 代码对比
|
|
25
20
|
|
|
26
|
-
<
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
21
|
+
<h4 align=center>esm.html</h4>
|
|
22
|
+
写法略微复杂
|
|
23
|
+
|
|
24
|
+
```html
|
|
25
|
+
<!DOCTYPE html>
|
|
26
|
+
<html lang="en">
|
|
27
|
+
<head>
|
|
28
|
+
<meta charset="UTF-8">
|
|
29
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
30
|
+
<title>esm</title>
|
|
31
|
+
<style>
|
|
32
|
+
button {
|
|
33
|
+
font-size: larger;
|
|
34
|
+
}
|
|
35
|
+
</style>
|
|
36
|
+
</head>
|
|
37
|
+
<body>
|
|
38
|
+
<div id="app">
|
|
39
|
+
<button @click="count++">{{ count }}</button>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<script type="module">
|
|
43
|
+
import { createApp, defineComponent, ref } from 'https://unpkg.com/vue/dist/vue.esm-browser.js';
|
|
44
|
+
const App = defineComponent(() => {
|
|
45
|
+
const count = ref(0);
|
|
46
|
+
return {
|
|
47
|
+
count
|
|
48
|
+
};
|
|
49
|
+
});
|
|
50
|
+
createApp(App).mount('#app')
|
|
51
|
+
</script>
|
|
52
|
+
</body>
|
|
53
|
+
</html>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
<h4 align=center>setup.vue</h4>
|
|
57
|
+
无法直接在浏览器运行
|
|
58
|
+
|
|
59
|
+
```html
|
|
60
|
+
<script setup>
|
|
61
|
+
import { ref } from 'vue'
|
|
62
|
+
const count = ref(0)
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<button @click="count++">{{ count }}</button>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<style>
|
|
70
|
+
button {
|
|
71
|
+
font-size: larger;
|
|
72
|
+
}
|
|
73
|
+
</style>
|
|
74
|
+
```
|
|
30
75
|
|
|
31
|
-
|
|
76
|
+
<h4 align=center>setupin.html</h4>
|
|
77
|
+
合二为一
|
|
78
|
+
|
|
79
|
+
```html
|
|
80
|
+
<head>
|
|
81
|
+
<meta charset="UTF-8">
|
|
82
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
83
|
+
<title>setupin</title>
|
|
84
|
+
<script src="https://unpkg.com/setupin"></script>
|
|
85
|
+
</head>
|
|
86
|
+
|
|
87
|
+
<script setup>
|
|
88
|
+
import { ref } from 'vue'
|
|
89
|
+
const count = ref(0)
|
|
90
|
+
</script>
|
|
91
|
+
|
|
92
|
+
<template>
|
|
93
|
+
<button @click="count++">{{ count }}</button>
|
|
94
|
+
</template>
|
|
95
|
+
|
|
96
|
+
<style>
|
|
97
|
+
button {
|
|
98
|
+
font-size: larger;
|
|
99
|
+
}
|
|
100
|
+
</style>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
除了\<head>之外和[\<script setup>](https://cn.vuejs.org/api/sfc-script-setup.html)写法完全一致
|
|
32
104
|
|
|
33
105
|
## 🤓 特性
|
|
34
106
|
|
|
35
|
-
- [x] 支持 esm import 语法
|
|
36
107
|
- [x] [顶层 await](https://cn.vuejs.org/api/sfc-script-setup.html#top-level-await)
|
|
37
108
|
- [x] [CSS 功能](https://cn.vuejs.org/api/sfc-css-features)
|
|
38
|
-
- [
|
|
109
|
+
- [ ] 拆分 [组件](https://cn.vuejs.org/guide/essentials/component-basics.html)
|
|
110
|
+
|
|
111
|
+
## 🤔 为什么选择 setupin
|
|
112
|
+
|
|
113
|
+
1. **便于学习**
|
|
114
|
+
为初学者提供一个友好的环境,帮助他们轻松上手 Vue 的核心用法。
|
|
115
|
+
|
|
116
|
+
2. **简易开发**
|
|
117
|
+
提供便捷的方式,助力快速开发小网页,无需繁琐的配置。
|
|
118
|
+
|
|
119
|
+
3. **快速体验**
|
|
120
|
+
让用户可以快速在 HTML 中尝试 Vue 的新特性,感受其魅力。
|
|
39
121
|
|
|
40
122
|
## 😝 演练场
|
|
41
123
|
|
package/dist/main.js
CHANGED
|
@@ -51,30 +51,25 @@ var __async = (__this, __arguments, generator) => {
|
|
|
51
51
|
};
|
|
52
52
|
(function() {
|
|
53
53
|
"use strict";
|
|
54
|
-
const ASCII_LOGO = "/***************************************\r\n** _ _ **\r\n** ___ ___| |_ _ _ _ __ (_)_ __ **\r\n** / __|/ _ \\ __| | | | '_ \\| | '_ \\ **\r\n** \\__ \\ __/ |_| |_| | |_/ | | | | | **\r\n** |___/\\___|\\__|\\__,_| .__/|_|_| |_| **\r\n** |_| **\r\n***************************************/\r\n";
|
|
54
|
+
const ASCII_LOGO = "\r\n/***************************************\r\n** _ _ **\r\n** ___ ___| |_ _ _ _ __ (_)_ __ **\r\n** / __|/ _ \\ __| | | | '_ \\| | '_ \\ **\r\n** \\__ \\ __/ |_| |_| | |_/ | | | | | **\r\n** |___/\\___|\\__|\\__,_| .__/|_|_| |_| **\r\n** |_| **\r\n***************************************/\r\n";
|
|
55
55
|
const APP_VAR_NAME = "APP$";
|
|
56
56
|
const REPO_NAME = "setupin";
|
|
57
|
-
const IMPORTS_JSON = JSON.stringify({
|
|
58
|
-
imports: {
|
|
59
|
-
vue: "https://unpkg.com/vue/dist/vue.runtime.esm-browser.js"
|
|
60
|
-
}
|
|
61
|
-
});
|
|
57
|
+
const IMPORTS_JSON = JSON.stringify({ imports: { vue: "https://unpkg.com/vue@latest/dist/vue.runtime.esm-browser.js" } });
|
|
62
58
|
const INIT_CODE = `
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
let ${APP_VAR_NAME} = {}
|
|
67
|
-
<\/script>
|
|
68
|
-
`;
|
|
69
|
-
const CREATE_ASYNC_APP_CODE = `
|
|
70
|
-
const { createApp, h, Suspense } = Vue
|
|
71
|
-
createApp({
|
|
72
|
-
render: () => h(Suspense, null, { default: () => h(${APP_VAR_NAME}) })
|
|
73
|
-
}).mount(document.body)
|
|
59
|
+
${ASCII_LOGO}
|
|
60
|
+
import * as Vue from "vue";
|
|
61
|
+
let ${APP_VAR_NAME} = Object.create(null);
|
|
74
62
|
`;
|
|
75
63
|
const CREATE_APP_CODE = `
|
|
76
|
-
|
|
77
|
-
|
|
64
|
+
Vue.createApp(Vue.defineComponent(
|
|
65
|
+
String(${APP_VAR_NAME}.setup).startsWith('async')
|
|
66
|
+
? () => () =>
|
|
67
|
+
Vue.h(Vue.Suspense, null, {
|
|
68
|
+
default: Vue.h(${APP_VAR_NAME}),
|
|
69
|
+
fallback: Vue.h('div', 'Loading...'),
|
|
70
|
+
})
|
|
71
|
+
: ${APP_VAR_NAME}
|
|
72
|
+
)).mount(document.body)
|
|
78
73
|
`;
|
|
79
74
|
/**
|
|
80
75
|
* @vue/compiler-sfc v3.5.12
|
|
@@ -45880,22 +45875,24 @@ ${exposeCall}`
|
|
|
45880
45875
|
const id = REPO_NAME;
|
|
45881
45876
|
function compilerSfc(source) {
|
|
45882
45877
|
var _a2, _b2;
|
|
45883
|
-
const sfcParseResult = parse$2(
|
|
45878
|
+
const sfcParseResult = parse$2(source, { filename });
|
|
45884
45879
|
sfcParseResult.errors.forEach((e) => {
|
|
45885
45880
|
console.warn(e);
|
|
45886
45881
|
});
|
|
45887
|
-
const sfcScriptBlock = compileScript(sfcParseResult.descriptor, { id });
|
|
45882
|
+
const sfcScriptBlock = compileScript(sfcParseResult.descriptor, { id, isProd: false });
|
|
45888
45883
|
const sfcTemplateCompileResults = compileTemplate({
|
|
45889
45884
|
id,
|
|
45890
45885
|
filename,
|
|
45891
|
-
source: (_b2 = (_a2 = sfcParseResult.descriptor.template) == null ? void 0 : _a2.content) != null ? _b2 : ""
|
|
45886
|
+
source: (_b2 = (_a2 = sfcParseResult.descriptor.template) == null ? void 0 : _a2.content) != null ? _b2 : "",
|
|
45887
|
+
isProd: false
|
|
45892
45888
|
});
|
|
45893
45889
|
const sfcStyleCompileResultsList = sfcParseResult.descriptor.styles.map((style) => {
|
|
45894
45890
|
return compileStyle({
|
|
45895
45891
|
id,
|
|
45896
45892
|
filename,
|
|
45897
45893
|
source: style.content,
|
|
45898
|
-
scoped: style.scoped
|
|
45894
|
+
scoped: style.scoped,
|
|
45895
|
+
isProd: false
|
|
45899
45896
|
});
|
|
45900
45897
|
});
|
|
45901
45898
|
return {
|
|
@@ -45906,7 +45903,7 @@ ${exposeCall}`
|
|
|
45906
45903
|
}
|
|
45907
45904
|
function createDom(row, inner) {
|
|
45908
45905
|
var _a2;
|
|
45909
|
-
const container2 = document.createElement("
|
|
45906
|
+
const container2 = document.createElement("body");
|
|
45910
45907
|
container2.insertAdjacentHTML("afterbegin", row);
|
|
45911
45908
|
const sample = container2.firstElementChild;
|
|
45912
45909
|
const dom = document.createElement(sample.tagName);
|
|
@@ -45915,9 +45912,7 @@ ${exposeCall}`
|
|
|
45915
45912
|
dom.setAttribute(n2, (_a2 = sample.getAttribute(n2)) != null ? _a2 : "");
|
|
45916
45913
|
}
|
|
45917
45914
|
return {
|
|
45918
|
-
mount(el)
|
|
45919
|
-
el.appendChild(dom);
|
|
45920
|
-
}
|
|
45915
|
+
mount: (el) => el.appendChild(dom)
|
|
45921
45916
|
};
|
|
45922
45917
|
}
|
|
45923
45918
|
function watchRoot(handler) {
|
|
@@ -45941,13 +45936,18 @@ ${exposeCall}`
|
|
|
45941
45936
|
}
|
|
45942
45937
|
function awaitCompileSfc(handler) {
|
|
45943
45938
|
return __async(this, null, function* () {
|
|
45944
|
-
const
|
|
45945
|
-
if (
|
|
45946
|
-
|
|
45947
|
-
|
|
45948
|
-
|
|
45939
|
+
const clientCodeList = yield watchRoot((node2, clientCodeList2) => {
|
|
45940
|
+
if (!/^(?:script|template|style)$/.test(node2.localName))
|
|
45941
|
+
return;
|
|
45942
|
+
if (node2.hasAttribute("src"))
|
|
45943
|
+
return;
|
|
45944
|
+
clientCodeList2.push(node2.outerHTML);
|
|
45945
|
+
node2.localName === "style" ? node2.onload = node2.remove : node2.remove();
|
|
45949
45946
|
});
|
|
45950
|
-
const
|
|
45947
|
+
const hasScript = clientCodeList.some((code) => code.slice(1, 7) === "script");
|
|
45948
|
+
if (!hasScript)
|
|
45949
|
+
clientCodeList.push("<script>/* empty script */<\/script>");
|
|
45950
|
+
const { sfcScriptBlock, sfcTemplateCompileResults, sfcStyleCompileResultsList } = compilerSfc(clientCodeList.join("\n"));
|
|
45951
45951
|
handler(sfcStyleCompileResultsList, sfcScriptBlock, sfcTemplateCompileResults);
|
|
45952
45952
|
});
|
|
45953
45953
|
}
|
|
@@ -45956,27 +45956,27 @@ ${exposeCall}`
|
|
|
45956
45956
|
}
|
|
45957
45957
|
function generateEsmCode(sfcScriptBlock, sfcTemplateCompileResults) {
|
|
45958
45958
|
return `
|
|
45959
|
+
${INIT_CODE}
|
|
45959
45960
|
${_scriptTransform(sfcScriptBlock)}
|
|
45960
45961
|
${_templateTransform(sfcTemplateCompileResults)}
|
|
45961
|
-
|
|
45962
|
-
else{${CREATE_APP_CODE}}
|
|
45962
|
+
${CREATE_APP_CODE}
|
|
45963
45963
|
`;
|
|
45964
|
+
function _scriptTransform(sfcScriptBlock2) {
|
|
45965
|
+
const s = new MagicString(sfcScriptBlock2.content);
|
|
45966
|
+
s.replace("export default", `${APP_VAR_NAME} =`);
|
|
45967
|
+
s.replace("Object.defineProperty(__returned__,", "// ");
|
|
45968
|
+
return s.toString();
|
|
45969
|
+
}
|
|
45970
|
+
function _templateTransform(sfcTemplateCompileResults2) {
|
|
45971
|
+
const t = new MagicString(sfcTemplateCompileResults2.code);
|
|
45972
|
+
t.replace("export function render", `${APP_VAR_NAME}.render = function`);
|
|
45973
|
+
return t.toString();
|
|
45974
|
+
}
|
|
45964
45975
|
}
|
|
45965
|
-
|
|
45966
|
-
const s = new MagicString(sfcScriptBlock.content);
|
|
45967
|
-
s.replace("export default", `${APP_VAR_NAME} =`);
|
|
45968
|
-
s.replace("Object.defineProperty(__returned__,", "// ");
|
|
45969
|
-
return s.toString();
|
|
45970
|
-
}
|
|
45971
|
-
function _templateTransform(sfcTemplateCompileResults) {
|
|
45972
|
-
const t = new MagicString(sfcTemplateCompileResults.code);
|
|
45973
|
-
t.replace("export function render", `${APP_VAR_NAME}.render = function`);
|
|
45974
|
-
return t.toString();
|
|
45975
|
-
}
|
|
45976
|
-
awaitCompileSfc((compiledStyles, ...compiledSetupAndRender) => {
|
|
45976
|
+
awaitCompileSfc((compiledStyleList, ...compiledSetupAndRender) => {
|
|
45977
45977
|
_toHead(`<script ${REPO_NAME} type="importmap">${IMPORTS_JSON}<\/script>`);
|
|
45978
45978
|
_toHead(`<script ${REPO_NAME} type="module">`, generateEsmCode(...compiledSetupAndRender));
|
|
45979
|
-
_toHead(`<style ${REPO_NAME}>`, generateStyleCode(
|
|
45979
|
+
_toHead(`<style ${REPO_NAME}>`, generateStyleCode(compiledStyleList));
|
|
45980
45980
|
});
|
|
45981
45981
|
function _toHead(...args) {
|
|
45982
45982
|
createDom(...args).mount(document.head);
|