diff --git a/packages/client/package.json b/packages/client/package.json
index 53814020d7..fefdacd888 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -27,6 +27,10 @@
"engines": {
"node": ">=18.0.0"
},
+ "scripts": {
+ "build": "vite build",
+ "dev": "vite build --watch"
+ },
"dependencies": {
"@antfu/utils": "^0.7.10",
"@iconify-json/carbon": "^1.1.36",
diff --git a/packages/client/uno.ts b/packages/client/uno.ts
new file mode 100644
index 0000000000..b959ab4424
--- /dev/null
+++ b/packages/client/uno.ts
@@ -0,0 +1,5 @@
+import '@unocss/reset/tailwind.css'
+import 'uno:preflights.css'
+import 'uno:typography.css'
+import 'uno:shortcuts.css'
+import 'uno.css'
diff --git a/packages/client/vite.config.ts b/packages/client/vite.config.ts
new file mode 100644
index 0000000000..0b88012e59
--- /dev/null
+++ b/packages/client/vite.config.ts
@@ -0,0 +1,114 @@
+import { fileURLToPath } from 'node:url'
+import { basename } from 'node:path'
+import { defineConfig, normalizePath } from 'vite'
+import UnoCSS from 'unocss/vite'
+import type { ResolvedSlidevOptions, SlidevPluginOptions } from '@slidev/types'
+import IconsResolver from 'unplugin-icons/resolver'
+import Components from 'unplugin-vue-components/vite'
+import fg from 'fast-glob'
+import { createInspectPlugin } from '../slidev/node/vite/inspect'
+import { createIconsPlugin } from '../slidev/node/vite/icons'
+import { createVuePlugin } from '../slidev/node/vite/vue'
+
+const absolute = (path: string) => normalizePath(fileURLToPath(new URL(path, import.meta.url)))
+const clientRoot = absolute('.')
+
+const options = {
+ clientRoot,
+ roots: [],
+ mode: 'build',
+ inspect: true,
+} as unknown as ResolvedSlidevOptions
+
+const pluginOptions = {
+ components: {
+ dts: false,
+ },
+} as SlidevPluginOptions
+
+const defines = [
+ '__DEV__',
+ '__SLIDEV_CLIENT_ROOT__',
+ '__SLIDEV_HASH_ROUTE__',
+ '__SLIDEV_FEATURE_DRAWINGS__',
+ '__SLIDEV_FEATURE_EDITOR__',
+ '__SLIDEV_FEATURE_DRAWINGS_PERSIST__',
+ '__SLIDEV_FEATURE_RECORD__',
+ '__SLIDEV_FEATURE_PRESENTER__',
+ '__SLIDEV_FEATURE_PRINT__',
+ '__SLIDEV_FEATURE_WAKE_LOCK__',
+ '__SLIDEV_HAS_SERVER__',
+]
+
+const builtinComponents = Object.fromEntries(fg.sync('*', {
+ cwd: absolute('./builtin'),
+ absolute: true,
+}).map(i => [`components/${basename(i).replace(/\..*$/, '')}`, i]))
+
+const layoutComponents = Object.fromEntries(fg.sync('*', {
+ cwd: absolute('./layouts'),
+ absolute: true,
+}).map(i => [`layouts/${basename(i).replace(/\..*$/, '')}`, i]))
+
+const externals = [
+ '#slidev/',
+ '/@slidev/',
+ '@slidev/',
+ 'server-reactive:',
+ 'vue',
+ 'vue-router',
+ 'monaco-editor',
+ 'typescript',
+ 'mermaid',
+ '~icons/',
+]
+
+export default defineConfig({
+ plugins: [
+ createInspectPlugin(options, pluginOptions),
+ UnoCSS(),
+ createVuePlugin(options, pluginOptions),
+ Components({
+ extensions: ['vue', 'ts'],
+ dirs: [absolute('./builtin')],
+ resolvers: [
+ IconsResolver({
+ prefix: '',
+ customCollections: Object.keys(pluginOptions.icons?.customCollections || []),
+ }),
+ ],
+ dts: false,
+ }),
+ createIconsPlugin(options, pluginOptions),
+ {
+ name: 'slidev:flags',
+ enforce: 'pre',
+ transform(code, id) {
+ if (id.match(/\.vue($|\?)/)) {
+ const original = code
+ defines.forEach((name) => {
+ code = code.replaceAll(`_ctx.${name}`, name)
+ })
+ if (original !== code)
+ return code
+ }
+ },
+ },
+ ],
+ build: {
+ lib: {
+ entry: {
+ 'main': absolute('./main.ts'),
+ 'index': absolute('./index.ts'),
+ 'uno.css': absolute('./uno.ts'),
+ ...builtinComponents,
+ ...layoutComponents,
+ },
+ formats: ['es'],
+ },
+ target: 'esnext',
+ rollupOptions: {
+ external: source => externals.some(i => source.startsWith(i)),
+ },
+ },
+})
diff --git a/packages/slidev/node/commands/shared.ts b/packages/slidev/node/commands/shared.ts
index c7f21f6c9c..69efd0ca13 100644
--- a/packages/slidev/node/commands/shared.ts
+++ b/packages/slidev/node/commands/shared.ts
@@ -66,7 +66,7 @@ export async function getIndexHtml({ mode, entry, clientRoot, roots, data }: Res
head += `\n`
main = main
- .replace('__ENTRY__', toAtFS(join(clientRoot, 'main.ts')))
+ .replace('__ENTRY__', toAtFS(join(clientRoot, 'dist/main.js')))
.replace('', head)
.replace('', body)
diff --git a/packages/slidev/node/options.ts b/packages/slidev/node/options.ts
index a76e19635e..0c1e9ccca6 100644
--- a/packages/slidev/node/options.ts
+++ b/packages/slidev/node/options.ts
@@ -84,8 +84,8 @@ export async function createDataUtils(data: SlidevData, clientRoot: string, root
const layouts: Record = {}
- for (const root of [clientRoot, ...roots]) {
- const layoutPaths = fg.sync('layouts/**/*.{vue,ts}', {
+ for (const root of [path.join(clientRoot, 'dist'), ...roots]) {
+ const layoutPaths = fg.sync('layouts/**/*.{vue,ts,js}', {
cwd: root,
absolute: true,
suppressErrors: true,
diff --git a/packages/slidev/node/virtual/styles.ts b/packages/slidev/node/virtual/styles.ts
index 5cdc262927..c9c3fefe4c 100644
--- a/packages/slidev/node/virtual/styles.ts
+++ b/packages/slidev/node/virtual/styles.ts
@@ -17,6 +17,7 @@ export const templateStyle: VirtualModuleTemplate = {
`import "${resolveUrlOfClient('styles/code.css')}"`,
`import "${resolveUrlOfClient('styles/katex.css')}"`,
`import "${resolveUrlOfClient('styles/transitions.css')}"`,
+ `import "${resolveUrlOfClient('dist/style.css')}"`,
]
for (const root of roots) {
diff --git a/packages/slidev/node/vite/compilerFlagsVue.ts b/packages/slidev/node/vite/compilerFlagsVue.ts
index 7d70a38afe..26b4174789 100644
--- a/packages/slidev/node/vite/compilerFlagsVue.ts
+++ b/packages/slidev/node/vite/compilerFlagsVue.ts
@@ -15,10 +15,10 @@ export function createVueCompilerFlagsPlugin(
name: 'slidev:flags',
enforce: 'pre',
transform(code, id) {
- if (id.match(/\.vue($|\?)/)) {
+ if (id.match(/\.vue($|\?)/) || id.includes('client/dist')) {
const original = code
define.forEach(([from, to]) => {
- code = code.replace(new RegExp(from, 'g'), to)
+ code = code.replaceAll(from, to)
})
if (original !== code)
return code
diff --git a/packages/slidev/node/vite/components.ts b/packages/slidev/node/vite/components.ts
index b7dfe2abdb..2ce8b01fc2 100644
--- a/packages/slidev/node/vite/components.ts
+++ b/packages/slidev/node/vite/components.ts
@@ -11,7 +11,7 @@ export function createComponentsPlugin(
extensions: ['vue', 'md', 'js', 'ts', 'jsx', 'tsx'],
dirs: [
- join(clientRoot, 'builtin'),
+ join(clientRoot, 'dist/components'),
...roots.map(i => join(i, 'components')),
],
diff --git a/packages/slidev/node/vite/extendConfig.ts b/packages/slidev/node/vite/extendConfig.ts
index 8a02be1c09..a5067565c8 100644
--- a/packages/slidev/node/vite/extendConfig.ts
+++ b/packages/slidev/node/vite/extendConfig.ts
@@ -68,7 +68,7 @@ export function createConfigPlugin(options: ResolvedSlidevOptions): Plugin {
})
return {
name: 'slidev:config',
- async config(config) {
+ async config() {
const injection: InlineConfig = {
define: getDefine(options),
resolve: {
@@ -188,7 +188,7 @@ export function createConfigPlugin(options: ResolvedSlidevOptions): Plugin {
injection.root = options.cliRoot
}
- return mergeConfig(injection, config)
+ return injection
},
configureServer(server) {
// serve our index.html after vite history fallback