diff --git a/packages/playground/esm-ssr/index.html b/packages/playground/esm-ssr/index.html
new file mode 100644
index 00000000000000..7968e96626c134
--- /dev/null
+++ b/packages/playground/esm-ssr/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Vite App
+
+
+
+
+
+
diff --git a/packages/playground/esm-ssr/package.json b/packages/playground/esm-ssr/package.json
new file mode 100644
index 00000000000000..8183b4ed05e7c5
--- /dev/null
+++ b/packages/playground/esm-ssr/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "test-prerender-esm-preact",
+ "private": true,
+ "version": "0.0.0",
+ "type": "module",
+ "scripts": {
+ "build": "vite build --ssr src/App.jsx"
+ },
+ "dependencies": {
+ "preact": "^10.5.13",
+ "preact-render-to-string": "^5.1.19"
+ },
+ "devDependencies": {
+ "@preact/preset-vite": "2.0.1",
+ "vite": "^2.2.3"
+ }
+}
diff --git a/packages/playground/esm-ssr/src/App.jsx b/packages/playground/esm-ssr/src/App.jsx
new file mode 100644
index 00000000000000..e79db198c281ac
--- /dev/null
+++ b/packages/playground/esm-ssr/src/App.jsx
@@ -0,0 +1,23 @@
+import { render } from 'preact-render-to-string';
+
+export function App() {
+ return (
+ <>
+ Hello Vite + Preact!
+
+
+ Learn Preact
+
+
+ >
+ )
+}
+
+export async function prerender() {
+ return await render();
+}
diff --git a/packages/playground/esm-ssr/vite.config.js b/packages/playground/esm-ssr/vite.config.js
new file mode 100644
index 00000000000000..45a2b1c7e63012
--- /dev/null
+++ b/packages/playground/esm-ssr/vite.config.js
@@ -0,0 +1,6 @@
+import { defineConfig } from 'vite'
+import preact from '@preact/preset-vite'
+
+export default defineConfig({
+ plugins: [preact.default()]
+})
diff --git a/packages/vite/src/node/build.ts b/packages/vite/src/node/build.ts
index abf067df13f4ff..661995300eeb59 100644
--- a/packages/vite/src/node/build.ts
+++ b/packages/vite/src/node/build.ts
@@ -164,6 +164,11 @@ export interface BuildOptions {
* `rollupOptions.input`.
*/
ssr?: boolean | string
+ /**
+ * When present, overrides the module format for the project to instead output
+ * the SSR in another format.
+ */
+ ssrFormat?: 'cjs' | 'es' | null
/**
* Generate SSR manifest for determining style links and asset preload
* directives in production.
@@ -220,6 +225,7 @@ export function resolveBuildOptions(raw?: BuildOptions): ResolvedBuildOptions {
manifest: false,
lib: false,
ssr: false,
+ ssrFormat: null,
ssrManifest: false,
brotliSize: true,
chunkSizeWarningLimit: 500,
@@ -332,6 +338,13 @@ async function doBuild(
)
}
+ const ssrFormat =
+ options.ssrFormat ||
+ (JSON.parse(fs.readFileSync(resolve('package.json'), 'utf-8')).type ===
+ 'module'
+ ? 'es'
+ : 'cjs')
+
const outDir = resolve(options.outDir)
// inject ssr arg to plugin load/transform hooks
@@ -399,12 +412,7 @@ async function doBuild(
const buildOutputOptions = (output: OutputOptions = {}): OutputOptions => {
return {
dir: outDir,
- format:
- ssr &&
- JSON.parse(fs.readFileSync(resolve('package.json'), 'utf-8')).type !=
- 'module'
- ? 'cjs'
- : 'es',
+ format: ssr ? ssrFormat : 'es',
exports: ssr ? 'named' : 'auto',
sourcemap: options.sourcemap,
name: libOptions ? libOptions.name : undefined,
diff --git a/packages/vite/src/node/cli.ts b/packages/vite/src/node/cli.ts
index 41ed363388d7a7..6457cc1550e44f 100644
--- a/packages/vite/src/node/cli.ts
+++ b/packages/vite/src/node/cli.ts
@@ -114,6 +114,10 @@ cli
'--ssr [entry]',
`[string] build specified entry for server-side rendering`
)
+ .option(
+ '-ssrFormat [format]',
+ '[string] SSR module format, either "cjs" or "es"'
+ )
.option(
'--sourcemap',
`[boolean] output source maps for build (default: false)`