diff --git a/files/entry.js b/files/entry.js index 01e128a..480d6d1 100644 --- a/files/entry.js +++ b/files/entry.js @@ -1,14 +1,25 @@ -import polka from 'polka'; -import compression from 'compression'; -import {getRequest, setResponse} from '@sveltejs/kit/node'; +import path from 'node:path'; // eslint-disable-next-line camelcase import {__fetch_polyfill} from '@sveltejs/kit/install-fetch'; -import {App} from 'APP'; -import {manifest} from './manifest.js'; +import {getRequest, setResponse} from '@sveltejs/kit/node'; +import compression from 'compression'; +import {manifest} from 'MANIFEST'; +import polka from 'polka'; +import sirv from 'sirv'; +import {Server} from 'SERVER'; __fetch_polyfill(); -const app = new App(manifest); +const app = new Server(manifest); + +// eslint-disable-next-line unicorn/prefer-module +const staticServe = sirv(path.join(__dirname, 'storage'), { + etag: true, + maxAge: 0, + immutable: false, + gzip: true, + brotli: true, +}); /** @type {import('polka').Middleware} */ function createKitMiddleware() { @@ -22,7 +33,7 @@ function createKitMiddleware() { return response.end(error.reason || 'Invalid request body'); } - setResponse(response, await app.render(request)); + setResponse(response, await app.respond(request)); }; } @@ -38,7 +49,9 @@ function getBase(headers) { const kitMiddleware = createKitMiddleware(); -const server = polka().use(compression({threshold: 0}), kitMiddleware); +const server = polka() + .use(staticServe) + .use(compression({threshold: 0}), kitMiddleware); const port = process.env.PORT || 8080; const listenOptions = {port}; diff --git a/index.js b/index.js index 15c646c..56dce52 100644 --- a/index.js +++ b/index.js @@ -32,7 +32,8 @@ export default function entrypoint() { // Copy server handler builder.copy(files, temporary, {replace: { - APP: `${relativePath}/app.js`, + SERVER: `${relativePath}/index.js`, + MANIFEST: './manifest.js', }}); writeFileSync( @@ -52,51 +53,18 @@ export default function entrypoint() { writeFileSync(`${dir}/package.json`, JSON.stringify({type: 'commonjs'})); - const serverRoutes = []; - - builder.createEntries(route => { - const parts = []; - - for (const segment of route.segments) { - if (segment.rest || segment.dynamic) { - parts.push('.*'); - } else { - parts.push(segment.content); - } - } - - const id = '/' + parts.join('/'); - - if (prerenderedPaths.paths.includes(id)) { - const staticPath = join('storage', id, 'index.html'); - serverRoutes.push( - { - url: id + '/?$', - // eslint-disable-next-line camelcase - static_files: staticPath, - upload: staticPath, - }, - ); - } else { - serverRoutes.push( - { - url: id, - secure: 'always', - script: 'auto', - }, - ); - } - - return { - id, - filter: _ => true, - complete: _ => {}, - }; - }); + const prerenderedPages = Array.from(prerenderedPaths.pages, ([src, page]) => ({ + url: src + '/?$', + // eslint-disable-next-line camelcase + static_files: 'storage/' + page.file, + upload: 'storage/' + page.file, + })); - if (serverRoutes.length > 99) { - throw new Error('Too many url routes: ' + serverRoutes.length); - } + const prerenderedRedirects = Array.from(prerenderedPaths.redirects, ([src, _]) => ({ + url: src, + secure: 'always', + script: 'auto', + })); // Load existing app.yaml if it exists let yaml = {}; @@ -105,21 +73,34 @@ export default function entrypoint() { yaml = YAML.parse(readFileSync('app.yaml').toString()); } + const serverRoutes = [ + ...yaml.handlers ?? [], + ...prerenderedPages, + ...prerenderedRedirects, + { + url: `/${builder.appDir}/.+`, + // eslint-disable-next-line camelcase + static_dir: `storage/${builder.appDir}`, + expiration: '30d 0h', + }, + { + url: '/.*', + secure: 'always', + script: 'auto', + }, + ]; + + if (serverRoutes.length > 99) { + throw new Error('Too many url routes: ' + serverRoutes.length); + } + writeFileSync( join(dir, 'app.yaml'), YAML.stringify({ ...yaml, runtime: 'nodejs16', entrypoint: 'node index.js', - handlers: [ - ...yaml.handlers ?? [], - ...serverRoutes, - { - url: '/', - // eslint-disable-next-line camelcase - static_dir: 'storage', - }, - ], + handlers: serverRoutes, }), ); diff --git a/package-lock.json b/package-lock.json index a67b7b8..2fd5fd9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "compression": "^1.7.4", "esbuild": "^0.13.4", "polka": "^1.0.0-next.22", + "sirv": "^2.0.2", "yaml": "^1.10.2" }, "devDependencies": { @@ -5268,6 +5269,14 @@ "node": ">=4" } }, + "node_modules/mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6380,6 +6389,19 @@ "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, + "node_modules/sirv": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", + "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "dependencies": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -6913,6 +6935,14 @@ "node": ">=8.0" } }, + "node_modules/totalist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", + "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==", + "engines": { + "node": ">=6" + } + }, "node_modules/trim-newlines": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", @@ -11323,6 +11353,11 @@ "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "peer": true }, + "mrmime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.0.tgz", + "integrity": "sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -12100,6 +12135,16 @@ "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, + "sirv": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.2.tgz", + "integrity": "sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==", + "requires": { + "@polka/url": "^1.0.0-next.20", + "mrmime": "^1.0.0", + "totalist": "^3.0.0" + } + }, "slash": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", @@ -12502,6 +12547,11 @@ "is-number": "^7.0.0" } }, + "totalist": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.0.tgz", + "integrity": "sha512-eM+pCBxXO/njtF7vdFsHuqb+ElbxqtI4r5EAvk6grfAFyJ6IvWlSkfZ5T9ozC6xWw3Fj1fGoSmrl0gUs46JVIw==" + }, "trim-newlines": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-4.0.2.tgz", diff --git a/package.json b/package.json index 69b2862..c454338 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "files" ], "peerDependencies": { - "@sveltejs/kit": ">=1.0.0-next.235" + "@sveltejs/kit": ">=1.0.0-next.280" }, "devDependencies": { "chai": "^4.3.4", @@ -48,6 +48,7 @@ "compression": "^1.7.4", "esbuild": "^0.13.4", "polka": "^1.0.0-next.22", + "sirv": "^2.0.2", "yaml": "^1.10.2" }, "xo": { diff --git a/tests/expected_app.yaml b/tests/expected_app.yaml index e54f734..bc77cd2 100644 --- a/tests/expected_app.yaml +++ b/tests/expected_app.yaml @@ -9,18 +9,13 @@ handlers: static_files: storage/index.html upload: storage/index.html - url: /about/?$ - static_files: storage/about/index.html - upload: storage/about/index.html - - url: /todos.json + static_files: storage/about.html + upload: storage/about.html + - url: /_app/.+ + static_dir: storage/_app + expiration: 30d 0h + - url: /.* secure: always script: auto - - url: /todos - secure: always - script: auto - - url: /todos/.* - secure: always - script: auto - - url: / - static_dir: storage runtime: nodejs16 entrypoint: node index.js diff --git a/tests/overwrites/svelte.config.js b/tests/overwrites/svelte.config.js index efc71c7..4ced66f 100644 --- a/tests/overwrites/svelte.config.js +++ b/tests/overwrites/svelte.config.js @@ -4,7 +4,6 @@ import adapter from 'svelte-adapter-appengine'; const config = { kit: { adapter: adapter(), - target: '#svelte', }, }; diff --git a/tests/test.js b/tests/test.js index 108e760..7b0585c 100644 --- a/tests/test.js +++ b/tests/test.js @@ -22,10 +22,10 @@ describe('Integration test', () => { it('runs endpoints', done => { chai.request('http://localhost:8080') - .get('/todos.json') + .get('/todos/__data.json') .end((error, response) => { expect(response).to.have.status(200); - expect(response.body).to.deep.equal([]); + expect(response.body).to.deep.equal({todos: []}); done(); }); }); diff --git a/tests/test.sh b/tests/test.sh index e786c25..11426f2 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -20,7 +20,7 @@ npm i npm i "${SCRIPT_PATH}/../" # These are peer dependencies that need manual install since we install from folder instead of from npm registry -npm install polka@1.0.0-next.22 compression@^1.7.4 +npm install polka@1.0.0-next.22 compression@^1.7.4 sirv@^2.0.2 npm run build