Skip to content

Commit

Permalink
feat: implement Node ESM loader
Browse files Browse the repository at this point in the history
  • Loading branch information
cyco130 committed Dec 20, 2022
1 parent 55972e5 commit 8a17526
Show file tree
Hide file tree
Showing 26 changed files with 526 additions and 67 deletions.
104 changes: 46 additions & 58 deletions ci/ci.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,75 +18,63 @@ const browser = await puppeteer.launch({
const pages = await browser.pages();
const page = pages[0];

const cases = [
{
framework: "simple-standalone",
env: "development",
file: "handler.ts",
},

{ framework: "simple-standalone", env: "production", file: "handler.ts" },

{ framework: "express", env: "development", file: "routes/home.ts" },
{ framework: "express", env: "production", file: "routes/home.ts" },

{ framework: "fastify", env: "development", file: "routes/home.ts" },
{ framework: "fastify", env: "production", file: "routes/home.ts" },

{ framework: "koa", env: "development", file: "routes/home.ts" },
{ framework: "koa", env: "production", file: "routes/home.ts" },

{ framework: "hapi", env: "development", file: "routes/home.ts" },
{ framework: "hapi", env: "production", file: "routes/home.ts" },

{
framework: "ssr-react-express",
env: "development",
file: "pages/Home.tsx",
},
{
framework: "ssr-react-express",
env: "production",
file: "pages/Home.tsx",
},
{
framework: "ssr-vue-express",
env: "development",
file: "pages/Home.vue",
},
{
framework: "ssr-vue-express",
env: "production",
file: "pages/Home.vue",
},
{
framework: "vite-plugin-ssr",
env: "development",
file: "pages/index/index.page.tsx",
},
{
framework: "vite-plugin-ssr",
env: "production",
file: "pages/index/index.page.tsx",
},
] as const;

describe.each(cases)("$framework - $env", ({ framework, env, file }) => {
const baseCases: Array<{
framework: string;
file: string;
}> = [
{ framework: "simple-standalone", file: "handler.ts" },
{ framework: "express", file: "routes/home.ts" },
{ framework: "fastify", file: "routes/home.ts" },
{ framework: "koa", file: "routes/home.ts" },
{ framework: "hapi", file: "routes/home.ts" },
{ framework: "ssr-react-express", file: "pages/Home.tsx" },
{ framework: "ssr-vue-express", file: "pages/Home.vue" },
{ framework: "vite-plugin-ssr", file: "pages/index/index.page.tsx" },
];

const [major, minor] = process.version
.slice(1)
.split(".")
.map((x) => Number(x));

const cases: Array<{
framework: string;
file: string;
env: "production" | "development" | "with-loader";
}> = [
...baseCases.map((x) => ({ ...x, env: "production" as const })),
...baseCases.map((x) => ({ ...x, env: "development" as const })),
];

const loaderAvailable = major > 16 || (major === 16 && minor >= 12);
if (loaderAvailable) {
cases.push(...baseCases.map((x) => ({ ...x, env: "with-loader" as const })));
}

describe.each(cases)("$framework - $env ", ({ framework, env, file }) => {
const ssr = framework.includes("ssr");
const dir = path.resolve(__dirname, "..", "examples", framework);

let cp: ChildProcess | undefined;

beforeAll(async () => {
const command =
env === "development"
? "pnpm exec vite serve --strictPort --port 3000 --logLevel silent"
: "pnpm run build && pnpm start";
env === "production"
? "pnpm run build && pnpm start"
: "pnpm exec vite serve --strictPort --port 3000 --logLevel silent";

cp = spawn(command, {
shell: true,
stdio: "inherit",
cwd: dir,
env: {
...process.env,
...(env === "with-loader" && {
NODE_OPTIONS:
(process.env.NODE_OPTIONS ?? "") +
" -r vavite/suppress-loader-warnings --loader vavite/node-loader",
}),
},
});

// Wait until server is ready
Expand Down Expand Up @@ -155,7 +143,7 @@ describe.each(cases)("$framework - $env", ({ framework, env, file }) => {
}, 15_000);
}

if (env === "development") {
if (env !== "production") {
test("hot reloads page", async () => {
await page.goto(TEST_HOST);

Expand Down
8 changes: 4 additions & 4 deletions examples/vite-plugin-ssr/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ startServer();
async function startServer() {
const app = express();

if (import.meta.env.PROD) {
if (!httpDevServer) {
app.use(express.static("dist/client"));
}

Expand All @@ -24,11 +24,11 @@ async function startServer() {
res.status(statusCode).send(body);
});

if (import.meta.env.PROD) {
if (httpDevServer) {
httpDevServer!.on("request", app);
} else {
const port = process.env.PORT || 3000;
app.listen(port);
console.log(`Server running at http://localhost:${port}`);
} else {
httpDevServer!.on("request", app);
}
}
7 changes: 7 additions & 0 deletions examples/vite-plugin-ssr/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,12 @@ export default defineConfig({
}),
react(),
ssr({ disableAutoFullBuild: true }),
{
name: "test",

configResolved(config) {
console.log(config.experimental);
},
},
],
});
4 changes: 4 additions & 0 deletions examples/with-loader/.stackblitzrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"installDependencies": true,
"startCommand": "npm run dev"
}
13 changes: 13 additions & 0 deletions examples/with-loader/entry-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from "express";

const app = express();

app.get("/foo", (req, res) => {
res.send("foo");
});

export default app;

if (typeof __vite_dev_server__ === "undefined") {
app.listen(3000, () => console.log("Listening on http://localhost:3000"));
}
20 changes: 20 additions & 0 deletions examples/with-loader/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "@vavite/example-with-loader",
"type": "module",
"private": true,
"scripts": {
"start": "node dist",
"dev": "vite",
"build": "vite build --ssr --mode=production"
},
"devDependencies": {
"@types/express": "^4.17.14",
"@types/node": "^18.11.14",
"@vavite/node-loader": "1.5.2",
"typescript": "^4.9.4",
"vite": "^4.0.1"
},
"dependencies": {
"express": "^4.18.2"
}
}
16 changes: 16 additions & 0 deletions examples/with-loader/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Vavite Simple Standalone example

Simplest example that specifies a `handlerEntry` and handles incoming requests.

> [Try on StackBlitz](https://stackblitz.com/github/cyco130/vavite/tree/main/examples/simple-standalone)
Clone with:

```bash
npx degit cyco130/vavite/examples/simple-standalone
```

> All examples have `"type": "module"` in their `package.json`.
>
> - For Vite v2, remove it to use CommonJS (CJS).
> - If you want to use CommonJS with Vite v3, add `legacy.buildSsrCjsExternalHeuristics: true` to your Vite config.
3 changes: 3 additions & 0 deletions examples/with-loader/some-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function greet(message: string) {
console.log(message);
}
11 changes: 11 additions & 0 deletions examples/with-loader/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"target": "es2020",
"module": "ESNext",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"moduleResolution": "Node"
}
}
42 changes: 42 additions & 0 deletions examples/with-loader/vite.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { defineConfig, ViteDevServer } from "vite";

declare global {
// eslint-disable-next-line no-var
var __vite_dev_server__: ViteDevServer | undefined;
}

export default defineConfig({
experimental: {
skipSsrTransform: true,
},
appType: "custom",
plugins: [
{
name: "vite-plugin-node-loader",
apply: "serve",
async configureServer(server) {
global.__vite_dev_server__ = server;

return () => {
server.middlewares.use(async (req, res, next) => {
const entry = await (
(0, eval)(`import("./entry-node?vavite-entry")`) as Promise<
typeof import("./entry-node")
>
).then((m) => m.default);

entry(req as any, res as any, next);
});
};
},
buildEnd() {
delete global.__vite_dev_server__;
},
config() {
return {
optimizeDeps: { include: [] },
};
},
},
],
});
3 changes: 3 additions & 0 deletions examples/with-loader/x.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.xxx {
background: green;
}
3 changes: 3 additions & 0 deletions examples/with-loader/y.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.main {
color: red;
}
27 changes: 26 additions & 1 deletion packages/connect/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import type { Plugin, UserConfig } from "vite";
import type { Plugin, UserConfig, ViteDevServer } from "vite";
import path from "path";
import url from "url";

declare global {
// eslint-disable-next-line no-var
var __vite_dev_server__: ViteDevServer | undefined;
// eslint-disable-next-line no-var
var __vavite_loader__: boolean;
}

const hasLoader = typeof __vavite_loader__ !== "undefined";

const dirname =
typeof __dirname === "undefined"
? url.fileURLToPath(new URL(".", import.meta.url))
Expand Down Expand Up @@ -84,6 +93,7 @@ export default function vaviteConnect(
// This silences the "could not auto-determine entry point" warning
include: [],
},
experimental: hasLoader ? { skipSsrTransform: true } : undefined,
};

if (env.command === "build" && config.build?.ssr) {
Expand Down Expand Up @@ -113,6 +123,15 @@ export default function vaviteConnect(
},

configureServer(server) {
if (hasLoader) {
global.__vite_dev_server__ = server;
server.ssrLoadModule = (id) => import(id + "?vavite-entry");
server.ssrFixStacktrace = () => {
/* noop */
};
server.ssrRewriteStacktrace = (s) => s;
}

function addMiddleware() {
server.middlewares.use(async (req, res) => {
function renderError(status: number, message: string) {
Expand Down Expand Up @@ -146,6 +165,12 @@ export default function vaviteConnect(
addMiddleware();
}
},

buildEnd() {
if (hasLoader) {
global.__vite_dev_server__ = undefined;
}
},
},
];
}
Expand Down
3 changes: 2 additions & 1 deletion packages/expose-vite-dev-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export default function vaviteDevServerPlugin(): Plugin {
resolveId(source, _importer, options) {
if (
(source === "@vavite/expose-vite-dev-server/vite-dev-server" ||
source === "vavite/vite-dev-server") &&
source === "vavite/vite-dev-server" ||
source === "virtual:vavite-vite-dev-server") &&
dev &&
options.ssr
) {
Expand Down
6 changes: 6 additions & 0 deletions packages/node-loader/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
require("@cyco130/eslint-config/patch");

module.exports = {
extends: ["@cyco130/eslint-config/node"],
parserOptions: { tsconfigRootDir: __dirname },
};
7 changes: 7 additions & 0 deletions packages/node-loader/lint-staged.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
"**/*.ts?(x)": [
() => "tsc -p tsconfig.json --noEmit",
"eslint --max-warnings 0 --ignore-pattern dist",
],
"*": "prettier --ignore-unknown --write",
};
Loading

0 comments on commit 8a17526

Please sign in to comment.