Skip to content

Commit 01c47d9

Browse files
committed
feat(bundler-farm): mvp
1 parent ca5f969 commit 01c47d9

File tree

15 files changed

+928
-7
lines changed

15 files changed

+928
-7
lines changed

.github/workflows/e2e.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
os: [ubuntu-latest, windows-latest, macos-latest]
1818
node: ['18', '20', '22']
19-
bundler: ['webpack', 'vite']
19+
bundler: ['webpack', 'farm', 'vite']
2020

2121
runs-on: ${{ matrix.os }}
2222

e2e/docs/.vuepress/config.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import process from 'node:process'
2+
import { farmBundler } from '@vuepress/bundler-farm'
23
import { viteBundler } from '@vuepress/bundler-vite'
34
import { webpackBundler } from '@vuepress/bundler-webpack'
45
import { defineUserConfig } from 'vuepress'
@@ -62,13 +63,15 @@ export default defineUserConfig({
6263
bundler:
6364
E2E_BUNDLER === 'webpack'
6465
? webpackBundler()
65-
: viteBundler({
66-
viteOptions: {
67-
optimizeDeps: {
68-
include: ['@vuepress-e2e/conditional-exports'],
66+
: E2E_BUNDLER === 'farm'
67+
? farmBundler()
68+
: viteBundler({
69+
viteOptions: {
70+
optimizeDeps: {
71+
include: ['@vuepress-e2e/conditional-exports'],
72+
},
6973
},
70-
},
71-
}),
74+
}),
7275

7376
theme: e2eTheme(),
7477

e2e/package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,24 @@
55
"type": "module",
66
"scripts": {
77
"docs:build": "vuepress build docs --clean-cache --clean-temp",
8+
"docs:build-farm": "cross-env E2E_BUNDLER=farm pnpm docs:build",
89
"docs:build-webpack": "cross-env E2E_BUNDLER=webpack pnpm docs:build",
910
"docs:clean": "rimraf docs/.vuepress/.temp docs/.vuepress/.cache docs/.vuepress/dist",
1011
"docs:dev": "vuepress dev docs --clean-cache --clean-temp",
12+
"docs:dev-farm": "cross-env E2E_BUNDLER=farm pnpm docs:dev",
1113
"docs:dev-webpack": "cross-env E2E_BUNDLER=webpack pnpm docs:dev",
1214
"docs:serve": "anywhere -s -h localhost -p 9080 -d docs/.vuepress/dist",
1315
"e2e:build": "cross-env E2E_COMMAND=build playwright test",
16+
"e2e:build-farm": "cross-env E2E_COMMAND=build E2E_BUNDLER=farm playwright test",
1417
"e2e:build-webpack": "cross-env E2E_COMMAND=build E2E_BUNDLER=webpack playwright test",
1518
"e2e:dev": "cross-env E2E_COMMAND=dev playwright test",
19+
"e2e:dev-farm": "cross-env E2E_COMMAND=dev E2E_BUNDLER=farm playwright test",
1620
"e2e:dev-webpack": "cross-env E2E_COMMAND=dev E2E_BUNDLER=webpack playwright test"
1721
},
1822
"dependencies": {
1923
"@vuepress-e2e/conditional-exports": "file:./modules/conditional-exports",
2024
"@vuepress-e2e/style-exports": "file:./modules/style-exports",
25+
"@vuepress/bundler-farm": "workspace:*",
2126
"@vuepress/bundler-vite": "workspace:*",
2227
"@vuepress/bundler-webpack": "workspace:*",
2328
"sass": "^1.77.6",

packages/bundler-farm/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @vuepress/bundler-farm
2+
3+
[![npm](https://badgen.net/npm/v/@vuepress/bundler-vite/next)](https://www.npmjs.com/package/@vuepress/bundler-farm)
4+
[![license](https://badgen.net/github/license/vuepress/core)](https://github.com/vuepress/core/blob/main/LICENSE)
5+
6+
## Documentation
7+
8+
https://v2.vuepress.vuejs.org
9+
10+
## License
11+
12+
[MIT](https://github.com/vuepress/core/blob/main/LICENSE)

packages/bundler-farm/client.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="@vuepress/vite-kit/client" />

packages/bundler-farm/package.json

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"name": "@vuepress/bundler-farm",
3+
"version": "2.0.0-rc.14",
4+
"description": "Bundler farm package of VuePress",
5+
"keywords": [
6+
"vuepress-bundler",
7+
"vuepress",
8+
"bundler",
9+
"farm"
10+
],
11+
"homepage": "https://github.com/vuepress",
12+
"bugs": {
13+
"url": "https://github.com/vuepress/core/issues"
14+
},
15+
"repository": {
16+
"type": "git",
17+
"url": "git+https://github.com/vuepress/core.git"
18+
},
19+
"license": "MIT",
20+
"author": "meteorlxy",
21+
"type": "module",
22+
"exports": {
23+
".": "./dist/index.js",
24+
"./client": "./client.d.ts",
25+
"./package.json": "./package.json"
26+
},
27+
"main": "./dist/index.js",
28+
"types": "./dist/index.d.ts",
29+
"files": [
30+
"dist",
31+
"client.d.ts"
32+
],
33+
"scripts": {
34+
"build": "tsup",
35+
"clean": "rimraf dist"
36+
},
37+
"dependencies": {
38+
"@farmfe/core": "^1.2.4",
39+
"@vuepress/client": "workspace:*",
40+
"@vuepress/core": "workspace:*",
41+
"@vuepress/utils": "workspace:*",
42+
"@vuepress/vite-kit": "workspace:*",
43+
"vue": "^3.4.29"
44+
},
45+
"devDependencies": {
46+
"rollup": "^4.18.0"
47+
},
48+
"publishConfig": {
49+
"access": "public"
50+
},
51+
"tsup": {
52+
"clean": true,
53+
"dts": "./src/index.ts",
54+
"entry": [
55+
"./src/index.ts"
56+
],
57+
"format": [
58+
"esm"
59+
],
60+
"outDir": "./dist",
61+
"sourcemap": false,
62+
"target": "es2022",
63+
"tsconfig": "../../tsconfig.dts.json"
64+
}
65+
}

packages/bundler-farm/src/build.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { build as farmBuild } from '@farmfe/core'
2+
import type { App, Bundler } from '@vuepress/core'
3+
import { debug, fs, withSpinner } from '@vuepress/utils'
4+
import { resolveFarmConfig } from './resolveFarmConfig.js'
5+
import type { FarmBundlerOptions } from './types.js'
6+
7+
const log = debug('vuepress:bundler-vite/build')
8+
9+
export const build = async (
10+
options: FarmBundlerOptions,
11+
app: App,
12+
): ReturnType<Bundler['build']> => {
13+
// plugin hook: extendsBundlerOptions
14+
await app.pluginApi.hooks.extendsBundlerOptions.process(options, app)
15+
16+
// vite compile
17+
log('compiling start')
18+
await withSpinner('Compiling with farm')(async () => {
19+
// create vite config
20+
const clientConfig = await resolveFarmConfig({
21+
app,
22+
options,
23+
isBuild: true,
24+
isServer: false,
25+
})
26+
const serverConfig = await resolveFarmConfig({
27+
app,
28+
options,
29+
isBuild: true,
30+
isServer: true,
31+
})
32+
33+
await Promise.all([farmBuild(clientConfig), farmBuild(serverConfig)])
34+
})
35+
log('compiling finish')
36+
37+
/*
38+
// render pages
39+
await withSpinner(`Rendering ${app.pages.length} pages`)(async (spinner) => {
40+
// get client bundle entry chunk and css asset
41+
const clientEntryChunk = clientOutput.output.find(
42+
(item) => item.type === 'chunk' && item.isEntry,
43+
) as OutputChunk
44+
const clientCssAsset = clientOutput.output.find(
45+
(item): item is OutputAsset =>
46+
item.type === 'asset' && item.fileName.endsWith('.css'),
47+
)
48+
49+
// get server bundle entry chunk
50+
const serverEntryChunk = serverOutput.output.find(
51+
(item) => item.type === 'chunk' && item.isEntry,
52+
) as OutputChunk
53+
54+
// load the compiled server bundle
55+
const serverEntryPath = app.dir.temp('.server', serverEntryChunk.fileName)
56+
const { createVueApp } = await importFile<{
57+
createVueApp: CreateVueAppFunction
58+
}>(serverEntryPath)
59+
// create vue ssr app
60+
const { app: vueApp, router: vueRouter } = await createVueApp()
61+
const { renderToString } = await import('vue/server-renderer')
62+
63+
// load ssr template file
64+
const ssrTemplate = await fs.readFile(app.options.templateBuild, {
65+
encoding: 'utf8',
66+
})
67+
68+
// pre-render pages to html files
69+
for (const page of app.pages) {
70+
if (spinner) spinner.text = `Rendering pages ${colors.magenta(page.path)}`
71+
await renderPage({
72+
app,
73+
page,
74+
vueApp,
75+
vueRouter,
76+
renderToString,
77+
ssrTemplate,
78+
output: clientOutput.output,
79+
outputEntryChunk: clientEntryChunk,
80+
outputCssAsset: clientCssAsset,
81+
})
82+
}
83+
})
84+
*/
85+
86+
// keep the server bundle files in debug mode
87+
if (!app.env.isDebug) {
88+
// remove server temp directory after pages rendered
89+
await fs.remove(app.dir.temp('.server'))
90+
}
91+
}

packages/bundler-farm/src/dev.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Compiler, DEFAULT_HMR_OPTIONS, logger, Server } from '@farmfe/core'
2+
import type { App, Bundler } from '@vuepress/core'
3+
import { resolveFarmConfig } from './resolveFarmConfig.js'
4+
import type { FarmBundlerOptions } from './types.js'
5+
6+
export const dev = async (
7+
options: FarmBundlerOptions,
8+
app: App,
9+
): ReturnType<Bundler['dev']> => {
10+
// plugin hook: extendsBundlerOptions
11+
await app.pluginApi.hooks.extendsBundlerOptions.process(options, app)
12+
13+
const farmConfig = await resolveFarmConfig({
14+
app,
15+
options,
16+
isBuild: false,
17+
isServer: false,
18+
})
19+
20+
const compiler = new Compiler({ config: farmConfig.compilation })
21+
const server = new Server({ compiler, logger })
22+
// @ts-expect-error wrong types? todo
23+
await server.createDevServer({
24+
...farmConfig.server,
25+
hmr: DEFAULT_HMR_OPTIONS,
26+
})
27+
await server.listen()
28+
29+
return server.close.bind(server)
30+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import type { Bundler } from '@vuepress/core'
2+
import { build } from './build.js'
3+
import { dev } from './dev.js'
4+
import type { FarmBundlerOptions } from './types.js'
5+
6+
export const farmBundler = (options: FarmBundlerOptions = {}): Bundler => ({
7+
name: '@vuepress/bundler-farm',
8+
dev: (app) => dev(options, app),
9+
build: (app) => build(options, app),
10+
})

packages/bundler-farm/src/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { farmBundler } from './farmBundler.js'
2+
3+
export * from './types.js'
4+
export * from './farmBundler.js'
5+
export default farmBundler
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './vuepressUserConfigPlugin.js'
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { JsPlugin } from '@farmfe/core'
2+
import type { FarmBundlerOptions } from '../types.js'
3+
4+
/**
5+
* A plugin to allow user config to override vite config
6+
*/
7+
export const vuepressUserConfigPlugin = (
8+
options: FarmBundlerOptions,
9+
): JsPlugin => ({
10+
name: 'vuepress:user-config',
11+
config: () => options.farmOptions ?? {},
12+
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { App } from '@vuepress/core'
2+
import { vuepressMainPlugin, vuepressVuePlugin } from '@vuepress/vite-kit'
3+
import { vuepressUserConfigPlugin } from './plugins/index.js'
4+
import type { FarmBundlerOptions, FarmOptions } from './types.js'
5+
6+
export const resolveFarmConfig = async ({
7+
app,
8+
options,
9+
isBuild,
10+
isServer,
11+
}: {
12+
app: App
13+
options: FarmBundlerOptions
14+
isBuild: boolean
15+
isServer: boolean
16+
}): Promise<FarmOptions> => {
17+
return {
18+
clearScreen: false,
19+
...options.farmOptions,
20+
vitePlugins: [
21+
vuepressVuePlugin(options.vuePluginOptions ?? {}),
22+
vuepressMainPlugin({ app, isBuild, isServer }),
23+
vuepressUserConfigPlugin(options),
24+
...(options.farmOptions?.vitePlugins ?? []),
25+
],
26+
}
27+
}

packages/bundler-farm/src/types.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import type { Server, start } from '@farmfe/core'
2+
import type { VuePluginOptions } from '@vuepress/vite-kit'
3+
4+
export type FarmOptions = Exclude<Parameters<typeof start>[0], undefined>
5+
export type FarmDevServerOptions = Parameters<
6+
InstanceType<typeof Server>['createDevServer']
7+
>[0]
8+
9+
/**
10+
* Options for bundler-vite
11+
*/
12+
export interface FarmBundlerOptions {
13+
farmOptions?: FarmOptions
14+
vuePluginOptions?: VuePluginOptions
15+
}

0 commit comments

Comments
 (0)