├── .editorconfig
├── .eslintrc.js
├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── .husky
├── commit-msg
├── lint-stagedrc.js
└── pre-commit
├── .ls-lint.yml
├── README.md
├── commitlint.config.js
├── favicon.ico
├── index.html
├── package.json
├── pnpm-lock.yaml
├── src
├── App.vue
├── api
│ └── index.ts
├── components
│ └── Header.vue
├── const
│ ├── code.ts
│ ├── imports.ts
│ └── index.ts
├── main.ts
├── repl-store
│ └── index.ts
├── types
│ ├── dts
│ │ └── shims-vue.d.ts
│ ├── index.ts
│ └── replStore.ts
└── utils
│ ├── download
│ ├── index.ts
│ └── template
│ │ ├── Readme.md
│ │ ├── index.html
│ │ ├── main.js
│ │ ├── package.json
│ │ └── vite.config.js
│ ├── encode.ts
│ ├── index.ts
│ └── version.ts
├── tsconfig.json
└── vite.config.ts
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset=utf-8
5 | end_of_line=LF
6 | insert_final_newline=true
7 | indent_style=space
8 | indent_size=2
9 | max_line_length = 100
10 |
11 | [*.{yml,yaml,json}]
12 | indent_style = space
13 | indent_size = 2
14 |
15 | [*.md]
16 | trim_trailing_whitespace = false
17 |
18 | [Makefile]
19 | indent_style = tab
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | jest: true,
7 | es6: true,
8 | },
9 | parser: 'vue-eslint-parser',
10 | parserOptions: {
11 | parser: '@typescript-eslint/parser',
12 | sourceType: 'module',
13 | ecmaVersion: 2020,
14 | ecmaFeatures: {
15 | jsx: true,
16 | tsx: true,
17 | },
18 | },
19 | plugins: ['@typescript-eslint', 'import'],
20 | extends: [
21 | 'plugin:vue/vue3-recommended',
22 | 'eslint:recommended',
23 | 'plugin:import/recommended',
24 | 'plugin:import/typescript',
25 | 'plugin:@typescript-eslint/recommended',
26 | '@vue/eslint-config-typescript/recommended',
27 | ],
28 | globals: {
29 | defineProps: 'readonly',
30 | defineEmits: 'readonly',
31 | defineExpose: 'readonly',
32 | withDefaults: 'readonly',
33 | },
34 | rules: {
35 | quotes: ['error', 'single', { avoidEscape: true, allowTemplateLiterals: true }],
36 | 'no-console': 'off',
37 | 'no-debugger': 'warn',
38 | 'no-undef': 'off',
39 | 'no-unused-vars': 'off',
40 | '@typescript-eslint/no-unused-vars': ['error'],
41 | camelcase: ['error', { properties: 'never' }],
42 | semi: ['error', 'never'],
43 | 'sort-imports': [
44 | 'error',
45 | {
46 | ignoreDeclarationSort: true,
47 | },
48 | ],
49 | '@typescript-eslint/member-delimiter-style': [
50 | 'error',
51 | {
52 | multiline: {
53 | delimiter: 'none',
54 | requireLast: false,
55 | },
56 | singleline: {
57 | delimiter: 'semi',
58 | requireLast: false,
59 | },
60 | },
61 | ],
62 | 'import/no-unused-modules': 'error',
63 | 'import/no-unresolved': 'off',
64 |
65 | // vue
66 | 'vue/max-attributes-per-line': ['error', {
67 | 'singleline': {
68 | 'max': 1
69 | },
70 | 'multiline': {
71 | 'max': 1
72 | },
73 | }],
74 | 'vue/html-closing-bracket-spacing': 'error',
75 | 'vue/require-default-prop': 'error',
76 | 'vue/require-explicit-emits': 'error',
77 | },
78 | ignorePatterns: ['dist', 'node_modules'],
79 | }
80 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy Pages
2 | on:
3 | push:
4 | branches:
5 | - main
6 | jobs:
7 | build-and-deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - uses: actions/checkout@v2
11 |
12 | - name: Install pnpm
13 | uses: pnpm/action-setup@v2.0.1
14 | with:
15 | version: 6.23.2
16 |
17 | - name: Set node version to 16
18 | uses: actions/setup-node@v2
19 | with:
20 | node-version: 16
21 | cache: "pnpm"
22 |
23 | - run: pnpm install
24 |
25 | - name: Build
26 | run: pnpm run build
27 |
28 | - name: Deploy
29 | uses: JamesIves/github-pages-deploy-action@releases/v3
30 | with:
31 | ACCESS_TOKEN: ${{ secrets.PAGES_TOKEN }}
32 | BRANCH: gh-pages
33 | repositoryName: brenner8023/devui-playground
34 | FOLDER: dist
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | .pnpm-debug.log*
4 | dist
5 | src/types/dts/components.d.ts
6 | src/types/dts/auto-imports.d.ts
7 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | pnpm exec commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/lint-stagedrc.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | '*.{js,jsx,ts,tsx,vue}': ['eslint --fix'],
4 | }
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | pnpm run ls-lint && pnpm exec lint-staged -c .husky/lint-stagedrc.js
5 |
--------------------------------------------------------------------------------
/.ls-lint.yml:
--------------------------------------------------------------------------------
1 | ls:
2 | src/*:
3 | .dir: kebab-case
4 | .ts: camelCase
5 | .tsx: PascalCase
6 | .spec.ts: camelCase
7 | .d.ts: kebab-case
8 | .vue: PascalCase
9 | .md: PascalCase
10 |
11 | ignore:
12 | - node_modules
13 | - dist
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # devui-playground
2 |
3 | 基于`@vue/repl`实现
4 |
5 | ## 技术栈
6 |
7 | - `@vue/repl`
8 | - vue3.x
9 | - vite
10 | - unocss
11 | - typescript
12 | - pnpm
13 |
14 | ## 感谢
15 |
16 | - [element-plus-playground](//github.com/element-plus/element-plus-playground)
17 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | extends: ['@commitlint/config-conventional'],
4 | }
5 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevCloudFE/devui-playground/332de843e19d5847f8643b74c85bf9668da8b5fe/favicon.ico
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | DevUI Playground
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devui-playground",
3 | "version": "0.1.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "dev": "vite --host",
8 | "build": "vite build",
9 | "lint": "pnpm run ls-lint && pnpm run eslint",
10 | "eslint": "eslint --cache --fix ./src --ext .vue,.js,.ts,.tsx",
11 | "ls-lint": "ls-lint",
12 | "prepare": "husky install",
13 | "test": "echo \"Error: no test specified\" && exit 1"
14 | },
15 | "author": "",
16 | "license": "MIT",
17 | "devDependencies": {
18 | "@commitlint/cli": "^16.1.0",
19 | "@commitlint/config-conventional": "^16.0.0",
20 | "@ls-lint/ls-lint": "^1.10.0",
21 | "@types/file-saver": "^2.0.5",
22 | "@types/node": "^17.0.10",
23 | "@typescript-eslint/eslint-plugin": "^5.10.2",
24 | "@typescript-eslint/parser": "^5.10.2",
25 | "@vitejs/plugin-vue": "^2.1.0",
26 | "@vue/eslint-config-typescript": "^10.0.0",
27 | "eslint": "^8.8.0",
28 | "eslint-plugin-import": "^2.25.4",
29 | "eslint-plugin-vue": "^8.4.0",
30 | "husky": "^7.0.4",
31 | "lint-staged": "^12.3.3",
32 | "typescript": "^4.5.5",
33 | "unocss": "^0.22.5",
34 | "unplugin-auto-import": "^0.5.11",
35 | "unplugin-vue-components": "^0.17.14",
36 | "vite": "^2.7.13",
37 | "vite-plugin-inspect": "^0.3.13"
38 | },
39 | "dependencies": {
40 | "@idux/cdk": "^1.0.0-alpha.4",
41 | "@idux/components": "^1.0.0-alpha.5",
42 | "@vue/repl": "^1.0.0",
43 | "@vueuse/core": "^7.5.4",
44 | "compare-versions": "^4.1.3",
45 | "file-saver": "^2.0.5",
46 | "jszip": "^3.7.1",
47 | "vue": "^3.2.29"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
18 |
19 |
20 |
21 |
22 |
46 |
47 |
52 |
--------------------------------------------------------------------------------
/src/api/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export const fetchVersions = (pkg: string) => {
3 | return useFetch(
4 | `https://data.jsdelivr.com/v1/package/npm/${pkg}`, {
5 | initialData: [],
6 | afterFetch: (ctx) => ((ctx.data = ctx.data.versions), ctx),
7 | })
8 | .json().data
9 | }
10 |
--------------------------------------------------------------------------------
/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | DevUI Playground
5 |
6 |
7 |
11 |
12 |
13 | {{ item.name }}:
14 |
20 |
26 |
27 |
28 |
29 |
30 |
31 | Download
32 |
33 |
37 | Share
38 |
39 |
45 | GitHub
46 |
47 |
48 |
49 |
50 |
51 |
92 |
--------------------------------------------------------------------------------
/src/const/code.ts:
--------------------------------------------------------------------------------
1 |
2 | export const setupDevui = 'devui.js'
3 |
4 | export const devuiCode = `
5 | import { getCurrentInstance } from 'vue'
6 | import DevUI from 'vue-devui'
7 | import { ThemeServiceInit, infinityTheme } from 'devui-theme'
8 |
9 | const install = (app) => {
10 | app.use(DevUI)
11 | };
12 |
13 | const loadIconCss = () => {
14 | const link = document.createElement('link')
15 | link.rel = 'stylesheet'
16 | link.href = 'https://unpkg.com/@devui-design/icons@latest/icomoon/devui-icon.css'
17 | document.body.appendChild(link)
18 | }
19 |
20 | const loadCss = () => {
21 | const link = document.createElement('link')
22 | link.rel = 'stylesheet'
23 | link.href = '#DEVUI_CSS_HREF#'
24 | document.body.appendChild(link)
25 | }
26 |
27 | ThemeServiceInit({ infinityTheme }, 'infinityTheme')
28 |
29 | export const setupDevui = () => {
30 | const instance = getCurrentInstance()
31 | instance.appContext.app.use({ install })
32 | loadIconCss()
33 | loadCss()
34 | };`
35 |
36 | export const defaultFile = 'App.vue'
37 |
38 | export const defaultCode = `
39 |
40 | Hello, DevUI!
41 |
42 | Primary
43 | Disabled
44 |
45 |
46 | `
52 |
--------------------------------------------------------------------------------
/src/const/imports.ts:
--------------------------------------------------------------------------------
1 | import { VersionRecord } from '@/types'
2 |
3 | export const genImportsMap = (versions: VersionRecord) => {
4 | const { Vue, DevUI } = versions
5 |
6 | return {
7 | 'devui-theme': {
8 | pkg: 'devui-theme',
9 | version: 'latest',
10 | file: '/index.es.js',
11 | },
12 | 'vue-devui': {
13 | pkg: 'vue-devui',
14 | version: DevUI,
15 | file: '/vue-devui.es.js',
16 | },
17 | vue: {
18 | pkg: 'vue',
19 | version: Vue,
20 | file: '/dist/vue.esm-browser.js',
21 | },
22 | 'vue-router': {
23 | pkg: 'vue-router',
24 | version: 'latest',
25 | file: '/dist/vue-router.esm-browser.js',
26 | },
27 | '@floating-ui/dom': {
28 | pkg: '@floating-ui/dom',
29 | version: 'latest',
30 | file: '/dist/floating-ui.dom.esm.js',
31 | },
32 | '@floating-ui/core': {
33 | pkg: '@floating-ui/core',
34 | version: 'latest',
35 | file: '/dist/floating-ui.core.esm.js',
36 | },
37 | '@vueuse/core': {
38 | pkg: '@vueuse/core',
39 | version: 'latest',
40 | file: '/index.mjs',
41 | },
42 | '@vue/devtools-api': {
43 | pkg: '@vue/devtools-api',
44 | version: 'latest',
45 | file: '/lib/esm/index.js',
46 | },
47 | '@vueuse/shared': {
48 | pkg: '@vueuse/shared',
49 | version: 'latest',
50 | file: '/index.mjs',
51 | },
52 | 'vue-demi': {
53 | pkg: 'vue-demi',
54 | version: 'latest',
55 | file: '/lib/index.mjs',
56 | },
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/const/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export { devuiCode, defaultCode, setupDevui, defaultFile } from './code'
3 |
4 | export { genImportsMap } from './imports'
5 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import '@vue/repl/style.css'
3 | import 'uno.css'
4 | import '@idux/components/default.min.css'
5 |
6 | import {
7 | IDUX_ICON_DEPENDENCIES,
8 | addIconDefinitions,
9 | } from '@idux/components/icon'
10 |
11 | // 静态加载: `IDUX_ICON_DEPENDENCIES` 是 `@idux` 的部分组件默认所使用到图标,建议在此时静态引入。
12 | addIconDefinitions(IDUX_ICON_DEPENDENCIES)
13 |
14 | import App from './App.vue'
15 |
16 | createApp(App).mount('#app')
17 |
--------------------------------------------------------------------------------
/src/repl-store/index.ts:
--------------------------------------------------------------------------------
1 | import { reactive, watchEffect } from 'vue'
2 | import { File, compileFile } from '@vue/repl'
3 | import type { OutputModes, SFCOptions, Store, StoreState } from '@vue/repl'
4 | import type { PendingCompiler, ReplStoreParam, VersionKey, VersionRecord } from '@/types'
5 | import { defaultCode, defaultFile, devuiCode, genImportsMap, setupDevui } from '@/const'
6 | import { decodeData, encodeData, genLink } from '@/utils'
7 |
8 | const getInitFiles = (serializedState = '') => {
9 | let files: StoreState['files'] = {
10 | [defaultFile]: new File(defaultFile, defaultCode)
11 | }
12 | if (serializedState) {
13 | try {
14 | files = {}
15 | const res = JSON.parse(decodeData(serializedState))
16 | for (const filename of Object.keys(res)) {
17 | files[filename] = new File(filename, res[filename])
18 | }
19 | } catch (err) {
20 | console.log(err)
21 | console.log('Json parse error: src/repl-store/index.ts')
22 | }
23 | }
24 |
25 | return files
26 | }
27 |
28 | const genVueLink = (version: string) => {
29 | const compilerSfc = genLink(
30 | '@vue/compiler-sfc',
31 | version,
32 | '/dist/compiler-sfc.esm-browser.js',
33 | )
34 | const runtimeDom = genLink(
35 | '@vue/runtime-dom',
36 | version,
37 | '/dist/runtime-dom.esm-browser.js',
38 | )
39 |
40 | return {
41 | compilerSfc,
42 | runtimeDom,
43 | }
44 | }
45 |
46 | const genImports = (versions: VersionRecord) => {
47 | const deps = {
48 | ...genImportsMap(versions),
49 | }
50 |
51 | return Object.fromEntries(
52 | Object.entries(deps).map(([key, info]) => [key, genLink(info.pkg, info.version, info.file)])
53 | )
54 | }
55 |
56 | export class ReplStore implements Store {
57 | state: StoreState
58 | compiler!: typeof import('vue/compiler-sfc')
59 | options?: SFCOptions
60 | versions: VersionRecord
61 | initialShowOutput = false
62 | initialOutputMode: OutputModes = 'preview'
63 |
64 | private pendingCompiler: PendingCompiler = null
65 |
66 | constructor({
67 | serializedState = '',
68 | versions = { Vue: 'latest', DevUI: 'latest' },
69 | }: ReplStoreParam) {
70 | const files = getInitFiles(serializedState)
71 | const mainFile = files[defaultFile] ? defaultFile : Object.keys(files)[0]
72 | this.state = reactive({
73 | mainFile,
74 | files,
75 | activeFile: files[mainFile],
76 | errors: [],
77 | vueRuntimeURL: '',
78 | })
79 | this.versions = versions
80 | this.initImportMap()
81 | }
82 |
83 | private initImportMap() {
84 | if (!this.state.files['import-map.json']) {
85 | this.state.files['import-map.json'] = new File(
86 | 'import-map.json',
87 | JSON.stringify({ imports: {} }, null, 2)
88 | )
89 | }
90 | }
91 |
92 | async initStore() {
93 | await this.setVueVersion(this.versions.Vue)
94 | await this.setDevuiVersion(this.versions.DevUI)
95 |
96 | // this.state.files[setupDevui] = new File(
97 | // setupDevui,
98 | // devuiCode,
99 | // true
100 | // )
101 |
102 | watchEffect(() => compileFile(this, this.state.activeFile))
103 |
104 | for (const file of Object.keys(this.state.files)) {
105 | if (file !== defaultFile) {
106 | compileFile(this, this.state.files[file])
107 | }
108 | }
109 | }
110 |
111 | setActive(filename: string) {
112 | this.state.activeFile = this.state.files[filename]
113 | }
114 |
115 | // 新增文件
116 | public addFile(fileOrFilename: string | File) {
117 | const file = typeof fileOrFilename === 'string' ?
118 | new File(fileOrFilename) :
119 | fileOrFilename
120 | this.state.files[file.filename] = file
121 |
122 | if (!file.hidden) this.setActive(file.filename)
123 | }
124 |
125 | // 删除文件
126 | public deleteFile(filename: string) {
127 | if (window?.confirm(`Confirm to delete ${filename}?`)) {
128 | if (this.state.activeFile.filename === filename) {
129 | this.state.activeFile = this.state.files[this.state.mainFile]
130 | }
131 | delete this.state.files[filename]
132 | }
133 | }
134 |
135 | public getFiles() {
136 | const exported: Record = {}
137 | for (const filename of Object.keys(this.state.files)) {
138 | exported[filename] = this.state.files[filename].code
139 | }
140 | return exported
141 | }
142 |
143 | async setFiles(newFiles: Record, mainFile = defaultFile) {
144 | const files: Record = {}
145 | if (mainFile === defaultFile && !newFiles[mainFile]) {
146 | files[mainFile] = new File(mainFile, defaultCode)
147 | }
148 | for (const [filename, file] of Object.entries(newFiles)) {
149 | files[filename] = new File(filename, file)
150 | }
151 | for (const file of Object.values(files)) {
152 | await compileFile(this, file)
153 | }
154 | this.state.mainFile = mainFile
155 | this.state.files = files
156 | this.initImportMap()
157 | this.setActive(mainFile)
158 | }
159 |
160 | private setImportMap(map: { imports: Record }) {
161 | try {
162 | this.state.files['import-map.json'].code = JSON.stringify(map, null, 2)
163 | } catch (e) {
164 | this.state.errors = [
165 | `stringify error in import-map.json: ${(e as Error).message}`,
166 | ]
167 | }
168 | }
169 |
170 | serialize() {
171 | const arr = Object
172 | .entries(this.getFiles())
173 | .filter(([file]) => file !== setupDevui)
174 | .map(([file, content]) => {
175 | if (file === 'import-map.json') {
176 | try {
177 | const importMap = JSON.stringify(this.getImportMap())
178 | return [file, importMap]
179 | // eslint-disable-next-line no-empty
180 | } catch { }
181 | }
182 | return [file, content]
183 | })
184 | const data = JSON.stringify(Object.fromEntries(arr))
185 | return `#${encodeData(data)}`
186 | }
187 |
188 | getImportMap() {
189 | try {
190 | return JSON.parse(this.state.files['import-map.json'].code)
191 | } catch (e) {
192 | this.state.errors = [
193 | `Syntax error in import-map.json: ${(e as Error).message}`,
194 | ]
195 | return {}
196 | }
197 | }
198 |
199 | private addDeps() {
200 | const importMap = this.getImportMap()
201 | importMap.imports = {
202 | ...importMap.imports,
203 | ...genImports(this.versions),
204 | }
205 | this.setImportMap(importMap)
206 | }
207 |
208 | public async setVersion(key: VersionKey, version: string) {
209 | switch (key) {
210 | case 'DevUI':
211 | await this.setDevuiVersion(version)
212 | compileFile(this, this.state.files[setupDevui])
213 | break
214 | case 'Vue':
215 | await this.setVueVersion(version)
216 | break
217 | }
218 | }
219 |
220 | private async setDevuiVersion(version: string) {
221 | this.versions.DevUI = version
222 |
223 | const href = genLink('vue-devui', version, '/style.css')
224 |
225 | this.state.files[setupDevui] = new File(
226 | setupDevui,
227 | devuiCode.replace('#DEVUI_CSS_HREF#', href),
228 | true,
229 | )
230 |
231 | this.addDeps()
232 | }
233 |
234 | private async setVueVersion(version: string) {
235 | const { compilerSfc, runtimeDom } = genVueLink(version)
236 |
237 | this.pendingCompiler = import(/* @vite-ignore */compilerSfc)
238 | this.compiler = await this.pendingCompiler
239 | this.pendingCompiler = null
240 |
241 | this.state.vueRuntimeURL = runtimeDom
242 |
243 | this.versions.Vue = version
244 |
245 | this.addDeps()
246 | }
247 | }
248 |
--------------------------------------------------------------------------------
/src/types/dts/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | import type { DefineComponent } from 'vue'
3 | const component: DefineComponent
4 | export default component
5 | }
6 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export {
3 | ReplStoreParam,
4 | VersionKey,
5 | VersionRecord,
6 | PendingCompiler,
7 | } from './replStore'
8 |
--------------------------------------------------------------------------------
/src/types/replStore.ts:
--------------------------------------------------------------------------------
1 |
2 | export interface ReplStoreParam {
3 |
4 | /** @default '' */
5 | serializedState?: string
6 | versions?: VersionRecord
7 | }
8 |
9 | export type VersionKey = 'Vue' | 'DevUI'
10 | export type VersionRecord = Record
11 |
12 | export type PendingCompiler = Promise | null
13 |
--------------------------------------------------------------------------------
/src/utils/download/index.ts:
--------------------------------------------------------------------------------
1 | import { saveAs } from 'file-saver'
2 | import indexHtml from './template/index.html?raw'
3 | import mainJs from './template/main.js?raw'
4 | import pkgJson from './template/package.json?raw'
5 | import viteCfg from './template/vite.config.js?raw'
6 | import readme from './template/Readme.md?raw'
7 | import type { ReplStore } from '@/repl-store'
8 |
9 | export const downloadProject = async (store: ReplStore) => {
10 | const excludes = ['devui.js', 'import-map.json']
11 | const { default: JSZip } = await import('jszip')
12 | const jsZip = new JSZip()
13 |
14 | jsZip.file('index.html', indexHtml)
15 | jsZip.file('package.json', pkgJson)
16 | jsZip.file('vite.config.js', viteCfg)
17 | jsZip.file('README.md', readme)
18 |
19 | const srcFolder = jsZip.folder('src')
20 | srcFolder?.file('main.js', mainJs)
21 |
22 | const files = store.getFiles()
23 | for (const file in files) {
24 | if (excludes.includes(file)) {
25 | continue
26 | }
27 | let code = files[file]
28 | if (file === 'App.vue') {
29 | code = code
30 | .replace("import { setupDevui } from './devui.js'\n", '')
31 | .replace("// don't remove\n", '')
32 | .replace('setupDevui()\n', '')
33 | }
34 | srcFolder?.file(file, code)
35 | }
36 |
37 | const blob = await jsZip.generateAsync({ type: 'blob' })
38 | saveAs(blob, 'vue-devui-starter.zip')
39 | }
40 |
--------------------------------------------------------------------------------
/src/utils/download/template/Readme.md:
--------------------------------------------------------------------------------
1 | # Vue DevUI Starter
2 |
3 | This is a project template using [Vite](https://vitejs.dev/). It requires [Node.js](https://nodejs.org) v12+.
4 |
5 | To start:
6 |
7 | ```sh
8 | pnpm i
9 | pnpm run dev
10 | ```
11 |
--------------------------------------------------------------------------------
/src/utils/download/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vue DevUI Starter
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/src/utils/download/template/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import DevUI from 'vue-devui'
3 | import 'vue-devui/style.css'
4 |
5 | import App from './App.vue'
6 |
7 | createApp(App).use(DevUI).mount('#app')
8 |
--------------------------------------------------------------------------------
/src/utils/download/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devui-starter",
3 | "version": "0.0.0",
4 | "scripts": {
5 | "dev": "vite",
6 | "build": "vite build",
7 | "serve": "vite preview"
8 | },
9 | "dependencies": {
10 | "vue": "^3.2.0",
11 | "vue-devui": "latest"
12 | },
13 | "devDependencies": {
14 | "@vitejs/plugin-vue": "^2.1.0",
15 | "@vue/compiler-sfc": "^3.2.0",
16 | "vite": "^2.7.13"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/download/template/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 |
4 | export default defineConfig({
5 | plugins: [vue()],
6 | })
7 |
--------------------------------------------------------------------------------
/src/utils/encode.ts:
--------------------------------------------------------------------------------
1 |
2 | export const encodeData = (data: string): string => {
3 | return btoa(unescape(encodeURIComponent(data)))
4 | }
5 |
6 | export const decodeData = (base64: string): string => {
7 | return decodeURIComponent(escape(atob(base64)))
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export { decodeData, encodeData } from './encode'
3 |
4 | export { genLink, getVueVersions, getDevuiVersions } from './version'
5 |
6 | export { downloadProject } from './download'
7 |
--------------------------------------------------------------------------------
/src/utils/version.ts:
--------------------------------------------------------------------------------
1 |
2 | import { fetchVersions } from '@/api'
3 | import { compare } from 'compare-versions'
4 |
5 | export const genLink = (pkg: string, version?: string, file = '') => {
6 | const ver = version ? `@${version}` : ''
7 | return `https://unpkg.com/${pkg}${ver}${file}`
8 | }
9 |
10 | export const getVueVersions = () => {
11 | const versions = fetchVersions('vue')
12 | return computed(() => versions.value?.filter(ver => compare(ver, '3.2.34', '>=')))
13 | }
14 |
15 | export const getDevuiVersions = () => {
16 | const versions = fetchVersions('vue-devui')
17 | return computed(() => versions.value?.filter(ver => compare(ver, '1.0.0-rc.5', '>=')))
18 | }
19 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "lib": ["ESNext", "DOM"],
5 | "module": "ESNext",
6 | "rootDir": ".",
7 | "baseUrl": ".",
8 | "moduleResolution": "node",
9 | "resolveJsonModule": true,
10 | "outDir": "dist",
11 | "esModuleInterop": true,
12 | "sourceMap": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "strict": true,
15 | "noUnusedLocals": true,
16 | "skipLibCheck": true,
17 | "types": ["vite/client", "node"],
18 | "paths": {
19 | "@/*": ["src/*"]
20 | }
21 | },
22 | "include": ["src/**/*.ts", "src/**/*.vue"],
23 | "exclude": ["node_modules", "dist"]
24 | }
25 |
--------------------------------------------------------------------------------
/vite.config.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { defineConfig } from 'vite'
3 | import Unocss from 'unocss/vite'
4 | import { presetUno } from 'unocss'
5 | import vue from '@vitejs/plugin-vue'
6 | import Components from 'unplugin-vue-components/vite'
7 | import { IduxResolver } from 'unplugin-vue-components/resolvers'
8 | import AutoImport from 'unplugin-auto-import/vite'
9 | import Inspect from 'vite-plugin-inspect'
10 |
11 | const pathSrc = path.resolve(__dirname, 'src')
12 |
13 | export default defineConfig(async () => {
14 |
15 | return {
16 | base: './',
17 | resolve: {
18 | alias: {
19 | '@': pathSrc,
20 | },
21 | },
22 | server: {
23 | port: 2022,
24 | },
25 | plugins: [
26 | vue({
27 | reactivityTransform: `${pathSrc}/**/*`,
28 | }),
29 | AutoImport({
30 | imports: ['vue', '@vueuse/core'],
31 | resolvers: [IduxResolver()],
32 | dts: path.resolve(`${pathSrc}/types/dts`, 'auto-imports.d.ts'),
33 | }),
34 | Components({
35 | resolvers: [IduxResolver()],
36 | dts: path.resolve(`${pathSrc}/types/dts`, 'components.d.ts'),
37 | }),
38 | Unocss({
39 | presets: [presetUno()],
40 | }),
41 | Inspect(),
42 | ],
43 | }
44 | })
45 |
--------------------------------------------------------------------------------