Skip to content

Commit 7621697

Browse files
committed
Website: create new infra for develop+deploy
Create two scripts, run-build.mjs and run-server.mjs, which perform different but related tasks: * run-build.mjs copies website files into a new directory, ignoring files we don't want to deploy. This replaces prepare-for-publish. * run-server.mjs serves files over HTTP similar to what would be seen by run-build.mjs (e.g. ignored files aren't served). This replaces manually running `python3 -m http.server 9001`. Also, because I couldn't help myself, allow index.html to be written with EJS templating. This feature isn't used yet, but will be used in the future to factor duplication between index.html files.
1 parent 3fc9090 commit 7621697

File tree

15 files changed

+1890
-91
lines changed

15 files changed

+1890
-91
lines changed

.github/workflows/deploy-website.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@ jobs:
2525
name: web-demo-dist-${{ github.event.inputs.build_commit_id }}
2626
path: website/public/demo/dist/
2727
workflow: build-and-test-web-demo.yml
28+
29+
- name: install build dependencies
30+
run: cd website && yarn install --production
2831
- name: build site
29-
run: website/prepare-for-publish ./website-build
32+
run: cd website && yarn build
3033

3134
- name: publish to GitHub Pages
3235
uses: peaceiris/actions-gh-pages@v3
@@ -36,7 +39,7 @@ jobs:
3639
github_token: ${{ secrets.GITHUB_TOKEN }}
3740
keep_files: false
3841
publish_branch: gh-pages
39-
publish_dir: ./website-build
42+
publish_dir: ./website/www
4043

4144
# quick-lint-js finds bugs in JavaScript programs.
4245
# Copyright (C) 2020 Matthew Glazar

website/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
/build-emscripten/
22
/node_modules/
3+
/www/

website/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,30 @@
11
# quick-lint-js website
22

33
This directory contains the source code for quick-lint-js' website.
4+
5+
## Developing
6+
7+
Hack on the website locally by running a local web server:
8+
9+
$ cd website # Navigate to this directory.
10+
$ yarn # Install dependencies.
11+
$ yarn start
12+
Server running: http://127.0.0.1:9001/
13+
14+
Open after starting the local web server, open http://127.0.0.1:9001/ in your
15+
browser.
16+
17+
If you want to work on the demo, see [demo documentation](demo/README.md).
18+
19+
## Packaging for deployment
20+
21+
Prepare the website for publishing on GitHub pages by running `yarn build`:
22+
23+
$ cd website # Navigate to this directory.
24+
$ yarn # Install dependencies.
25+
$ yarn build
26+
27+
Look at the copied and generated files in `website/www/`.
28+
29+
For instructions on deploying to quick-lint-js.com, see the [release
30+
documentation](docs/RELEASE.md).

website/package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
{
22
"scripts": {
3+
"build": "node --experimental-modules run-build.mjs www",
34
"fmt": "prettier --write '**/*.css' '**/*.html' '**/*.js' '**/*.mjs'",
5+
"start": "node --experimental-modules run-server.mjs 9001",
46
"test": "node --experimental-modules run-tests.mjs"
57
},
8+
"engines": {
9+
"node": ">=14.14.0"
10+
},
11+
"dependencies": {
12+
"ejs": "^3.1.6",
13+
"express": "^4.17.1",
14+
"mime": "^2.5.2",
15+
"morgan": "^1.10.0"
16+
},
617
"devDependencies": {
18+
"axios": "^0.21.1",
719
"colors": "^1.4.0",
820
"jasmine": "^3.7.0",
921
"jsdom": "16.4.0",

website/prepare-for-publish

Lines changed: 0 additions & 88 deletions
This file was deleted.

website/run-build.mjs

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (C) 2020 Matthew Glazar
2+
// See end of file for extended copyright information.
3+
4+
import fs from "fs";
5+
import path from "path";
6+
import url from "url";
7+
import { makeBuildInstructionsAsync } from "./src/build.mjs";
8+
import { Router, makeHTMLRedirect } from "./src/router.mjs";
9+
import { websiteConfig } from "./src/config.mjs";
10+
11+
let __filename = url.fileURLToPath(import.meta.url);
12+
let __dirname = path.dirname(__filename);
13+
14+
async function mainAsync() {
15+
let { targetDirectory } = parseArguments(process.argv.slice(2));
16+
17+
let wwwRootPath = websiteConfig.wwwRootPath;
18+
let instructions = await makeBuildInstructionsAsync(websiteConfig);
19+
let router = new Router(websiteConfig);
20+
21+
async function copyFileAsync(fromPath, toPath) {
22+
let from = path.relative("", path.resolve(wwwRootPath, fromPath));
23+
let to = path.relative("", path.resolve(targetDirectory, toPath));
24+
console.log(`copy: ${from} -> ${to}`);
25+
await fs.promises.mkdir(path.dirname(to), { recursive: true });
26+
await fs.promises.writeFile(to, await fs.promises.readFile(from));
27+
}
28+
29+
for (let instruction of instructions) {
30+
switch (instruction.type) {
31+
case "copy":
32+
await copyFileAsync(instruction.path, instruction.path);
33+
break;
34+
35+
case "copy-to":
36+
await copyFileAsync(
37+
instruction.sourcePath,
38+
instruction.destinationPath
39+
);
40+
break;
41+
42+
case "build-ejs":
43+
let ejsPath = path.join(wwwRootPath, instruction.sourcePath);
44+
let outPath = path.join(targetDirectory, instruction.destinationPath);
45+
console.log(`build EJS: ${ejsPath} -> ${outPath}`);
46+
await fs.promises.mkdir(path.dirname(outPath), { recursive: true });
47+
let out = await router.renderEJSFile(ejsPath);
48+
fs.promises.writeFile(outPath, out);
49+
break;
50+
51+
case "html-redirect":
52+
let htmlPath = path.join(targetDirectory, instruction.htmlPath);
53+
await fs.promises.mkdir(path.dirname(htmlPath), { recursive: true });
54+
console.log(
55+
`redirect: ${htmlPath} -> ${instruction.redirectTargetURL}`
56+
);
57+
await fs.promises.writeFile(
58+
htmlPath,
59+
makeHTMLRedirect(instruction.htmlPath, instruction.redirectTargetURL)
60+
);
61+
break;
62+
63+
default:
64+
throw new Error(
65+
`Unexpected type from makeBuildInstructionsAsync: ${instruction.type}`
66+
);
67+
}
68+
}
69+
}
70+
71+
function parseArguments(args) {
72+
let targetDirectory;
73+
switch (args.length) {
74+
case 1:
75+
targetDirectory = args[0];
76+
break;
77+
78+
default:
79+
throw new Error("Expected exactly 1 argument");
80+
}
81+
return { targetDirectory };
82+
}
83+
84+
mainAsync().catch((error) => {
85+
console.error(error.stack);
86+
process.exit(1);
87+
});
88+
89+
// quick-lint-js finds bugs in JavaScript programs.
90+
// Copyright (C) 2020 Matthew Glazar
91+
//
92+
// This file is part of quick-lint-js.
93+
//
94+
// quick-lint-js is free software: you can redistribute it and/or modify
95+
// it under the terms of the GNU General Public License as published by
96+
// the Free Software Foundation, either version 3 of the License, or
97+
// (at your option) any later version.
98+
//
99+
// quick-lint-js is distributed in the hope that it will be useful,
100+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
101+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
102+
// GNU General Public License for more details.
103+
//
104+
// You should have received a copy of the GNU General Public License
105+
// along with quick-lint-js. If not, see <https://www.gnu.org/licenses/>.

website/run-server.mjs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Copyright (C) 2020 Matthew Glazar
2+
// See end of file for extended copyright information.
3+
4+
import express from "express";
5+
import http from "http";
6+
import morgan from "morgan";
7+
import path from "path";
8+
import url from "url";
9+
import { listenAsync, urlFromServerAddress } from "./src/net.mjs";
10+
import { makeServer } from "./src/server.mjs";
11+
import { websiteConfig } from "./src/config.mjs";
12+
13+
let __filename = url.fileURLToPath(import.meta.url);
14+
let __dirname = path.dirname(__filename);
15+
16+
async function mainAsync() {
17+
let { host, port } = parseArguments(process.argv.slice(2));
18+
19+
let app = express();
20+
app.use(morgan("dev"));
21+
app.use(makeServer(websiteConfig));
22+
23+
let server = http.createServer(app);
24+
await listenAsync(server, { host: host, port: port });
25+
console.log(`Server running: ${urlFromServerAddress(server.address())}`);
26+
}
27+
28+
function parseArguments(args) {
29+
let host = "localhost";
30+
let port = 0;
31+
switch (args.length) {
32+
case 0:
33+
break;
34+
35+
case 1:
36+
port = parseInt(args[0]);
37+
if (isNaN(port)) {
38+
throw new Error(`Expected port number, but got: ${args[0]}`);
39+
}
40+
break;
41+
42+
case 2:
43+
host = args[0];
44+
port = parseInt(args[1]);
45+
if (isNaN(port)) {
46+
throw new Error(`Expected port number, but got: ${args[1]}`);
47+
}
48+
break;
49+
50+
default:
51+
throw new Error("Too many arguments; expected 0, 1, or 2");
52+
}
53+
return { host, port };
54+
}
55+
56+
mainAsync().catch((error) => {
57+
console.error(error.stack);
58+
process.exit(1);
59+
});
60+
61+
// quick-lint-js finds bugs in JavaScript programs.
62+
// Copyright (C) 2020 Matthew Glazar
63+
//
64+
// This file is part of quick-lint-js.
65+
//
66+
// quick-lint-js is free software: you can redistribute it and/or modify
67+
// it under the terms of the GNU General Public License as published by
68+
// the Free Software Foundation, either version 3 of the License, or
69+
// (at your option) any later version.
70+
//
71+
// quick-lint-js is distributed in the hope that it will be useful,
72+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
73+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
74+
// GNU General Public License for more details.
75+
//
76+
// You should have received a copy of the GNU General Public License
77+
// along with quick-lint-js. If not, see <https://www.gnu.org/licenses/>.

0 commit comments

Comments
 (0)