diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index 8894d046c6a4..1d573d33c13d 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -1,5 +1,5 @@ -const { copyFileSync } = require('fs'); -const { join } = require('path'); +import { copyFileSync } from 'fs'; +import { join } from 'path'; /** * @param {{ diff --git a/packages/adapter-node/package.json b/packages/adapter-node/package.json index 3cfb7059ace5..fe94a20b9cb3 100644 --- a/packages/adapter-node/package.json +++ b/packages/adapter-node/package.json @@ -2,12 +2,14 @@ "name": "@sveltejs/adapter-node", "version": "1.0.0-next.11", "main": "index.js", + "type": "module", "files": [ "files" ], "scripts": { "dev": "rollup -cw", "build": "rollup -c", + "test": "uvu tests", "lint": "eslint --ignore-path .gitignore \"**/*.{ts,js,svelte}\" && npm run check-format", "format": "prettier --write . --config ../../.prettierrc --ignore-path .gitignore", "check-format": "prettier --check . --config ../../.prettierrc --ignore-path .gitignore", @@ -17,9 +19,11 @@ "@rollup/plugin-json": "^4.1.0", "@sveltejs/kit": "workspace:*", "compression": "^1.7.4", + "node-fetch": "^2.6.1", "polka": "^1.0.0-next.13", "rollup": "^2.41.1", "sirv": "^1.0.11", - "typescript": "^4.2.3" + "typescript": "^4.2.3", + "uvu": "^0.5.1" } } diff --git a/packages/adapter-node/rollup.config.js b/packages/adapter-node/rollup.config.js index 1ae7ff01d547..dd33517bc2fc 100644 --- a/packages/adapter-node/rollup.config.js +++ b/packages/adapter-node/rollup.config.js @@ -3,7 +3,7 @@ import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; export default { - input: 'src/server.js', + input: 'src/index.js', output: { file: 'files/server.js', format: 'esm', diff --git a/packages/adapter-node/src/index.js b/packages/adapter-node/src/index.js new file mode 100644 index 000000000000..82112e1cbdd1 --- /dev/null +++ b/packages/adapter-node/src/index.js @@ -0,0 +1,15 @@ +import { createServer } from './server'; +/*eslint import/no-unresolved: [2, { ignore: ['\.\/app\.js$'] }]*/ +import * as app from './app.js'; + +const { PORT = 3000 } = process.env; // TODO configure via svelte.config.js + +const instance = createServer({ render: app.render }).listen(PORT, (err) => { + if (err) { + console.log('error', err); + } else { + console.log(`Listening on port ${PORT}`); + } +}); + +export { instance }; diff --git a/packages/adapter-node/src/server.js b/packages/adapter-node/src/server.js index 15947db4918e..9168ff0d5f3d 100644 --- a/packages/adapter-node/src/server.js +++ b/packages/adapter-node/src/server.js @@ -7,51 +7,55 @@ import { URL, fileURLToPath } from 'url'; // eslint-disable-next-line import/no-unresolved import { get_body } from '@sveltejs/kit/http'; // App is a dynamic file built from the application layer. -/*eslint import/no-unresolved: [2, { ignore: ['\.\/app\.js$'] }]*/ -import * as app from './app.js'; const __dirname = dirname(fileURLToPath(import.meta.url)); - -const { PORT = 3000 } = process.env; // TODO configure via svelte.config.js - -const mutable = (dir) => - sirv(dir, { - etag: true, - maxAge: 0 - }); - const noop_handler = (_req, _res, next) => next(); - -const prerendered_handler = fs.existsSync('prerendered') ? mutable('prerendered') : noop_handler; - -const assets_handler = sirv(join(__dirname, '/assets'), { - maxAge: 31536000, - immutable: true -}); - -polka() - .use(compression({ threshold: 0 }), assets_handler, prerendered_handler, async (req, res) => { - const parsed = new URL(req.url || '', 'http://localhost'); - const rendered = await app.render({ - method: req.method, - headers: req.headers, // TODO: what about repeated headers, i.e. string[] - path: parsed.pathname, - body: await get_body(req), - query: parsed.searchParams +const paths = { + assets: join(__dirname, '/assets'), + prerendered: join(__dirname, '/prerendered'), +}; + +export function createServer({ render }) { + const mutable = (dir) => + sirv(dir, { + etag: true, + maxAge: 0 }); - if (rendered) { - res.writeHead(rendered.status, rendered.headers); - res.end(rendered.body); - } else { - res.statusCode = 404; - res.end('Not found'); + const prerendered_handler = fs.existsSync(paths.prerendered) + ? mutable(paths.prerendered) + : noop_handler; + + const assets_handler = fs.existsSync(paths.assets) + ? sirv(paths.assets), { + maxAge: 31536000, + immutable: true + }) + : noop_handler; + + const server = polka().use( + compression({ threshold: 0 }), + assets_handler, + prerendered_handler, + async (req, res) => { + const parsed = new URL(req.url || '', 'http://localhost'); + const rendered = await render({ + method: req.method, + headers: req.headers, // TODO: what about repeated headers, i.e. string[] + path: parsed.pathname, + body: await get_body(req), + query: parsed.searchParams + }); + + if (rendered) { + res.writeHead(rendered.status, rendered.headers); + res.end(rendered.body); + } else { + res.statusCode = 404; + res.end('Not found'); + } } - }) - .listen(PORT, (err) => { - if (err) { - console.log('error', err); - } else { - console.log(`Listening on port ${PORT}`); - } - }); + ); + + return server; +} diff --git a/packages/adapter-node/tests/smoke.js b/packages/adapter-node/tests/smoke.js new file mode 100644 index 000000000000..196313205910 --- /dev/null +++ b/packages/adapter-node/tests/smoke.js @@ -0,0 +1,33 @@ +import { test } from 'uvu'; +import { createServer } from '../src/server.js'; +import * as assert from 'uvu/assert'; +import fetch from 'node-fetch'; + +const { PORT = 3000 } = process.env; + +function startServer() { + const server = createServer({ render: () => {} }); + return new Promise((fulfil, reject) => { + server.listen(PORT, (err) => { + if (err) { + reject(err); + } + fulfil(server); + }); + }); +} + +test('starts a server', async () => { + const server = await startServer(); + assert.ok('server started'); + server.server.close(); +}); + +test('serves a 404', async () => { + const server = await startServer(); + const res = await fetch(`http://localhost:${PORT}/nothing`); + assert.equal(res.status, 404); + server.server.close(); +}); + +test.run(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bbb385eeab2..381f59083443 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -116,18 +116,22 @@ importers: '@rollup/plugin-json': 4.1.0_rollup@2.41.1 '@sveltejs/kit': link:../kit compression: 1.7.4 + node-fetch: 2.6.1 polka: 1.0.0-next.13 rollup: 2.41.1 sirv: 1.0.11 typescript: 4.2.3 + uvu: 0.5.1 specifiers: '@rollup/plugin-json': ^4.1.0 '@sveltejs/kit': workspace:* compression: ^1.7.4 + node-fetch: ^2.6.1 polka: ^1.0.0-next.13 rollup: ^2.41.1 sirv: ^1.0.11 typescript: ^4.2.3 + uvu: ^0.5.1 packages/adapter-static: devDependencies: '@sveltejs/kit': link:../kit @@ -2492,7 +2496,6 @@ packages: resolution: integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== /node-fetch/2.6.1: - dev: false engines: node: 4.x || >=6.0.0 resolution: