Production ready build (#175)

- Rename `public` -> `client` so it doesn't get copied automagically as-is (without hashes which we want for cache busting), https://vitejs.dev/guide/assets.html#the-public-directory
     - We still build the version files to `public/` so their copied as-is and Vite handles it for us (so we can use `emptyOutDir`) 
 - Use a multiple entrypoint `.js` Vite build so things can be more intelligently bundled and take less time
     - We aren't using library mode because it doesn't minify or bundle assets
 - Using hash asset tags for cache busting. Hash of the file included in the file name
 - We lookup these hashed assets from `manifest.json` that Vite builds (https://vitejs.dev/guide/backend-integration.html) to serve and preload
 - In terms of optimized bundles, I know the current output isn't great now but will have to opt to fix that up separately in the future. Tracked by https://github.com/matrix-org/matrix-public-archive/issues/176
This commit is contained in:
Eric Eastwood 2023-04-24 23:50:53 -05:00 committed by GitHub
parent 50a1d658e8
commit 9c0b6fe85e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 1112 additions and 366 deletions

2
.gitignore vendored
View File

@ -1,7 +1,7 @@
node_modules
.DS_Store
dist
dist-ssr
public
*.local
config.user-overrides.json

View File

@ -4,7 +4,8 @@
# - https://github.com/npm/cli/issues/4769
FROM node:16.14.2-buster-slim
# Pass through some GitHub CI variables which we use in the build
# Pass through some GitHub CI variables which we use in the build (for version
# files/tags)
ARG GITHUB_SHA
ENV GITHUB_SHA=$GITHUB_SHA
ARG GITHUB_REF
@ -25,14 +26,13 @@ RUN npm install
# Copy what we need for the client-side build
COPY config /app/config/
COPY build-scripts /app/build-scripts/
COPY public /app/public/
COPY client /app/client/
COPY shared /app/shared/
# Also copy the server stuff (we reference the config from the `build-client.js`)
COPY server /app/server/
# Build the client-side bundle
RUN npm run build
# Copy the rest of the app
COPY server /app/server/
HEALTHCHECK CMD node docker-health-check.js
ENTRYPOINT ["/bin/bash", "-c", "npm start"]

View File

@ -1,38 +0,0 @@
'use strict';
// A way to build multiple Vite entrypoints
// We can remove this once Vite supports multiple entrypoints and
// https://github.com/vitejs/vite/pull/7047 lands. We can migrate back to a
// normal `vite.config.js` and what we had before.
//
// Related issues:
// - https://github.com/vitejs/vite/issues/4530
// - https://github.com/vitejs/vite/discussions/1736
const path = require('path');
const vite = require('vite');
const mergeOptions = require('merge-options');
const generateViteConfigForEntryPoint = require('./generate-vite-config-for-entry-point');
const entryPoints = [
path.resolve(__dirname, '../public/js/entry-client-hydrogen.js'),
path.resolve(__dirname, '../public/js/entry-client-room-directory.js'),
path.resolve(__dirname, '../public/js/entry-client-room-alias-hash-redirect.js'),
];
async function buildClientScripts(extraConfig = {}) {
for (const entryPoint of entryPoints) {
// Build the client-side JavaScript bundle when we see any changes
const viteConfig = mergeOptions(
generateViteConfigForEntryPoint(entryPoint),
// Since we're building multiple entryPoints, we don't want it to clear out for each one
{ build: { emptyOutDir: false } },
extraConfig
);
await vite.build(viteConfig);
}
}
module.exports = buildClientScripts;

View File

@ -1,10 +1,19 @@
'use strict';
const buildClientScripts = require('./build-client-scripts');
const writeVersionFiles = require('./write-version-files');
const vite = require('vite');
const mergeOptions = require('merge-options');
async function build(extraConfig) {
await Promise.all([writeVersionFiles(), buildClientScripts(extraConfig)]);
// Require the config before the Vite config so `process.env.NODE_ENV` is set
require('../server/lib/config');
const writeVersionFiles = require('./write-version-files');
const viteConfig = require('./vite.config');
async function buildClient(extraConfig = {}) {
await writeVersionFiles();
const resultantViteConfig = mergeOptions(viteConfig, extraConfig);
await vite.build(resultantViteConfig);
}
module.exports = build;
module.exports = buildClient;

View File

@ -1,44 +0,0 @@
// vite.config.js
'use strict';
const path = require('path');
const { defineConfig } = require('vite');
function generateViteConfigForEntryPoint(entryPoint) {
const entryPointName = path.basename(entryPoint, '.js');
return defineConfig({
// We have to specify this otherwise Vite will override NODE_ENV as
// `production` when we start the server and watch build in our `start-dev.js`.
mode: process.env.NODE_ENV || 'dev',
//root: './',
//base: './',
outDir: './dist',
// optimizeDeps: {
// include: ['matrix-public-archive-shared'],
// },
resolve: {
alias: {
// The `file:` packages don't seem resolve correctly so let's add an alias as well
// See https://css-tricks.com/adding-vite-to-your-existing-web-app/#aa-aliases
'matrix-public-archive-shared': path.resolve(__dirname, '../shared'),
},
},
build: {
// Fix `Error: 'default' is not exported by ...` when importin CommonJS files,
// see https://github.com/vitejs/vite/issues/2679
commonjsOptions: { include: [] },
lib: {
entry: entryPoint,
//formats: ['cjs'],
name: entryPointName,
fileName: (format) => `${entryPointName}.${format}.js`,
},
rollupOptions: {},
},
});
}
module.exports = generateViteConfigForEntryPoint;

View File

@ -0,0 +1,80 @@
// vite.config.js
'use strict';
const path = require('path');
const {
defineConfig, //splitVendorChunkPlugin
} = require('vite');
module.exports = defineConfig({
// We have to specify this otherwise Vite will override NODE_ENV as
// `production` when we start the server and watch build in our `start-dev.js`.
mode: process.env.NODE_ENV || 'dev',
plugins: [
// Alternatively, we can manually configure chunks via
// `build.rollupOptions.output.manualChunks`.
// Docs: https://vitejs.dev/guide/build.html#chunking-strategy
//
// This didn't seem to work for me though, so I've done the manual config way.
// splitVendorChunkPlugin(),
],
//root: './',
//base: './',
// optimizeDeps: {
// include: ['matrix-public-archive-shared'],
// },
resolve: {
alias: {
// The `file:` packages don't seem resolve correctly so let's add an alias as well
// See https://css-tricks.com/adding-vite-to-your-existing-web-app/#aa-aliases
'matrix-public-archive-shared': path.resolve(__dirname, '../shared'),
},
},
build: {
outDir: './dist',
rollupOptions: {
// Overwrite default `index.html` entry
// (https://vitejs.dev/guide/backend-integration.html#backend-integration)
input: [
path.resolve(__dirname, '../client/js/entry-client-hydrogen.js'),
path.resolve(__dirname, '../client/js/entry-client-room-directory.js'),
path.resolve(__dirname, '../client/js/entry-client-room-alias-hash-redirect.js'),
],
output: {
assetFileNames: (chunkInfo) => {
const { name } = path.parse(chunkInfo.name);
// Some of the Hydrogen assets already have hashes in the name so let's remove
// that in favor of our new hash.
const nameWithoutHash = name.replace(/-[a-z0-9]+$/, '');
return `assets/${nameWithoutHash}-[hash][extname]`;
},
},
},
// We want to know how the transformed source relates back to the original source
// for easier debugging
sourcemap: true,
// Generate `dist/manifest.json` that we can use to map a given file to it's built
// hashed file name and any dependencies it has.
manifest: true,
// We don't want to use the `ssrManifest` option. It's supposedly "for determining
// style links and asset preload directives in production"
// (https://vitejs.dev/config/build-options.html#build-ssrmanifest) (also see
// https://vitejs.dev/guide/ssr.html#generating-preload-directives) but doesn't seem
// very useful or what we want.
//
// ssrManifest: true,
// Copy things like the version files from `public/` to `dist/`
copyPublicDir: true,
// Fix `Error: 'default' is not exported by ...` when importing CommonJS files, see
// https://github.com/vitejs/vite/issues/2679 and docs:
// https://vitejs.dev/guide/dep-pre-bundling.html#monorepos-and-linked-dependencies
commonjsOptions: { include: [/shared/] },
},
});

View File

@ -38,10 +38,10 @@ async function writeVersionFiles() {
);
}
await mkdirp(path.join(__dirname, '../dist/'));
await writeFile(path.join(__dirname, '../dist/GIT_COMMIT'), commit);
await writeFile(path.join(__dirname, '../dist/VERSION'), branch);
await writeFile(path.join(__dirname, '../dist/VERSION_DATE'), new Date().toISOString());
await mkdirp(path.join(__dirname, '../public/'));
await writeFile(path.join(__dirname, '../public/GIT_COMMIT'), commit);
await writeFile(path.join(__dirname, '../public/VERSION'), branch);
await writeFile(path.join(__dirname, '../public/VERSION_DATE'), new Date().toISOString());
}
module.exports = writeVersionFiles;

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -0,0 +1,9 @@
import 'matrix-public-archive-shared/hydrogen-vm-render-script';
// Assets
// We have to disable no-missing-require lint because it doesn't take into
// account `package.json`. `exports`, see
// https://github.com/mysticatea/eslint-plugin-node/issues/255
// eslint-disable-next-line node/no-missing-import
import 'hydrogen-view-sdk/assets/theme-element-light.css';
import '../css/styles.css';

View File

@ -2,6 +2,14 @@ import assert from 'matrix-public-archive-shared/lib/assert';
import MatrixPublicArchiveURLCreator from 'matrix-public-archive-shared/lib/url-creator';
import redirectIfRoomAliasInHash from 'matrix-public-archive-shared/lib/redirect-if-room-alias-in-hash';
// Assets
// We have to disable no-missing-require lint because it doesn't take into
// account `package.json`. `exports`, see
// https://github.com/mysticatea/eslint-plugin-node/issues/255
// eslint-disable-next-line node/no-missing-import
import 'hydrogen-view-sdk/assets/theme-element-light.css';
import '../css/styles.css';
const config = window.matrixPublicArchiveContext.config;
assert(config);
assert(config.basePath);

View File

@ -0,0 +1,14 @@
import 'matrix-public-archive-shared/room-directory-vm-render-script';
// Assets
// We have to disable no-missing-require lint because it doesn't take into
// account `package.json`. `exports`, see
// https://github.com/mysticatea/eslint-plugin-node/issues/255
// eslint-disable-next-line node/no-missing-import
import 'hydrogen-view-sdk/assets/theme-element-light.css';
import '../css/styles.css';
import '../css/room-directory.css';
// Just need to reference the favicon in one of the entry points for it to be copied
// over for all
import '../img/favicon.ico';
import '../img/favicon.svg';

771
package-lock.json generated
View File

@ -41,12 +41,364 @@
"mocha": "^9.2.1",
"nodemon": "^2.0.15",
"prettier": "^2.8.7",
"vite": "^2.9.6"
"vite": "^4.3.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.17.tgz",
"integrity": "sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz",
"integrity": "sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.17.tgz",
"integrity": "sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz",
"integrity": "sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz",
"integrity": "sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz",
"integrity": "sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz",
"integrity": "sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz",
"integrity": "sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==",
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz",
"integrity": "sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz",
"integrity": "sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz",
"integrity": "sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==",
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz",
"integrity": "sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==",
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz",
"integrity": "sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==",
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz",
"integrity": "sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==",
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz",
"integrity": "sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==",
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz",
"integrity": "sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz",
"integrity": "sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz",
"integrity": "sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz",
"integrity": "sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz",
"integrity": "sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==",
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz",
"integrity": "sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==",
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz",
"integrity": "sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==",
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -2889,10 +3241,11 @@
}
},
"node_modules/esbuild": {
"version": "0.14.31",
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.17.tgz",
"integrity": "sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@ -2900,41 +3253,28 @@
"node": ">=12"
},
"optionalDependencies": {
"esbuild-android-64": "0.14.31",
"esbuild-android-arm64": "0.14.31",
"esbuild-darwin-64": "0.14.31",
"esbuild-darwin-arm64": "0.14.31",
"esbuild-freebsd-64": "0.14.31",
"esbuild-freebsd-arm64": "0.14.31",
"esbuild-linux-32": "0.14.31",
"esbuild-linux-64": "0.14.31",
"esbuild-linux-arm": "0.14.31",
"esbuild-linux-arm64": "0.14.31",
"esbuild-linux-mips64le": "0.14.31",
"esbuild-linux-ppc64le": "0.14.31",
"esbuild-linux-riscv64": "0.14.31",
"esbuild-linux-s390x": "0.14.31",
"esbuild-netbsd-64": "0.14.31",
"esbuild-openbsd-64": "0.14.31",
"esbuild-sunos-64": "0.14.31",
"esbuild-windows-32": "0.14.31",
"esbuild-windows-64": "0.14.31",
"esbuild-windows-arm64": "0.14.31"
}
},
"node_modules/esbuild-windows-64": {
"version": "0.14.31",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
"@esbuild/android-arm": "0.17.17",
"@esbuild/android-arm64": "0.17.17",
"@esbuild/android-x64": "0.17.17",
"@esbuild/darwin-arm64": "0.17.17",
"@esbuild/darwin-x64": "0.17.17",
"@esbuild/freebsd-arm64": "0.17.17",
"@esbuild/freebsd-x64": "0.17.17",
"@esbuild/linux-arm": "0.17.17",
"@esbuild/linux-arm64": "0.17.17",
"@esbuild/linux-ia32": "0.17.17",
"@esbuild/linux-loong64": "0.17.17",
"@esbuild/linux-mips64el": "0.17.17",
"@esbuild/linux-ppc64": "0.17.17",
"@esbuild/linux-riscv64": "0.17.17",
"@esbuild/linux-s390x": "0.17.17",
"@esbuild/linux-x64": "0.17.17",
"@esbuild/netbsd-x64": "0.17.17",
"@esbuild/openbsd-x64": "0.17.17",
"@esbuild/sunos-x64": "0.17.17",
"@esbuild/win32-arm64": "0.17.17",
"@esbuild/win32-ia32": "0.17.17",
"@esbuild/win32-x64": "0.17.17"
}
},
"node_modules/escalade": {
@ -3519,9 +3859,24 @@
"dev": true,
"license": "ISC"
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"license": "MIT"
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/get-caller-file": {
"version": "2.0.5",
@ -3649,7 +4004,8 @@
},
"node_modules/has": {
"version": "1.0.3",
"license": "MIT",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dependencies": {
"function-bind": "^1.1.1"
},
@ -3873,8 +4229,9 @@
}
},
"node_modules/is-core-module": {
"version": "2.8.1",
"license": "MIT",
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
"dependencies": {
"has": "^1.0.3"
},
@ -4411,9 +4768,16 @@
"license": "MIT"
},
"node_modules/nanoid": {
"version": "3.3.4",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"license": "MIT",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@ -4761,8 +5125,9 @@
},
"node_modules/picocolors": {
"version": "1.0.0",
"dev": true,
"license": "ISC"
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"node_modules/picomatch": {
"version": "2.3.1",
@ -4808,7 +5173,9 @@
"license": "MIT"
},
"node_modules/postcss": {
"version": "8.4.14",
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"dev": true,
"funding": [
{
@ -4818,11 +5185,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@ -5149,10 +5519,11 @@
"license": "MIT"
},
"node_modules/resolve": {
"version": "1.22.0",
"license": "MIT",
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"dependencies": {
"is-core-module": "^2.8.1",
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
@ -5214,14 +5585,16 @@
}
},
"node_modules/rollup": {
"version": "2.67.2",
"version": "3.20.6",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.6.tgz",
"integrity": "sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==",
"dev": true,
"license": "MIT",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
"node": ">=14.18.0",
"npm": ">=8.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
@ -5409,8 +5782,9 @@
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@ -5733,30 +6107,36 @@
}
},
"node_modules/vite": {
"version": "2.9.6",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.1.tgz",
"integrity": "sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.14.27",
"postcss": "^8.4.12",
"resolve": "^1.22.0",
"rollup": "^2.59.0"
"esbuild": "^0.17.5",
"postcss": "^8.4.21",
"rollup": "^3.20.2"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": ">=12.2.0"
"node": "^14.18.0 || >=16.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"sass": "*",
"stylus": "*"
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
@ -5765,6 +6145,12 @@
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
},
@ -5929,6 +6315,160 @@
"shared": {}
},
"dependencies": {
"@esbuild/android-arm": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.17.tgz",
"integrity": "sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==",
"dev": true,
"optional": true
},
"@esbuild/android-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz",
"integrity": "sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==",
"dev": true,
"optional": true
},
"@esbuild/android-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.17.tgz",
"integrity": "sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==",
"dev": true,
"optional": true
},
"@esbuild/darwin-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz",
"integrity": "sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==",
"dev": true,
"optional": true
},
"@esbuild/darwin-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz",
"integrity": "sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz",
"integrity": "sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==",
"dev": true,
"optional": true
},
"@esbuild/freebsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz",
"integrity": "sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz",
"integrity": "sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==",
"dev": true,
"optional": true
},
"@esbuild/linux-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz",
"integrity": "sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==",
"dev": true,
"optional": true
},
"@esbuild/linux-ia32": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz",
"integrity": "sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==",
"dev": true,
"optional": true
},
"@esbuild/linux-loong64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz",
"integrity": "sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==",
"dev": true,
"optional": true
},
"@esbuild/linux-mips64el": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz",
"integrity": "sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==",
"dev": true,
"optional": true
},
"@esbuild/linux-ppc64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz",
"integrity": "sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-riscv64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz",
"integrity": "sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==",
"dev": true,
"optional": true
},
"@esbuild/linux-s390x": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz",
"integrity": "sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==",
"dev": true,
"optional": true
},
"@esbuild/linux-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz",
"integrity": "sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==",
"dev": true,
"optional": true
},
"@esbuild/netbsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz",
"integrity": "sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==",
"dev": true,
"optional": true
},
"@esbuild/openbsd-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz",
"integrity": "sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==",
"dev": true,
"optional": true
},
"@esbuild/sunos-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz",
"integrity": "sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==",
"dev": true,
"optional": true
},
"@esbuild/win32-arm64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz",
"integrity": "sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==",
"dev": true,
"optional": true
},
"@esbuild/win32-ia32": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz",
"integrity": "sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==",
"dev": true,
"optional": true
},
"@esbuild/win32-x64": {
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz",
"integrity": "sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==",
"dev": true,
"optional": true
},
"@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
@ -7769,36 +8309,35 @@
}
},
"esbuild": {
"version": "0.14.31",
"version": "0.17.17",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.17.tgz",
"integrity": "sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==",
"dev": true,
"requires": {
"esbuild-android-64": "0.14.31",
"esbuild-android-arm64": "0.14.31",
"esbuild-darwin-64": "0.14.31",
"esbuild-darwin-arm64": "0.14.31",
"esbuild-freebsd-64": "0.14.31",
"esbuild-freebsd-arm64": "0.14.31",
"esbuild-linux-32": "0.14.31",
"esbuild-linux-64": "0.14.31",
"esbuild-linux-arm": "0.14.31",
"esbuild-linux-arm64": "0.14.31",
"esbuild-linux-mips64le": "0.14.31",
"esbuild-linux-ppc64le": "0.14.31",
"esbuild-linux-riscv64": "0.14.31",
"esbuild-linux-s390x": "0.14.31",
"esbuild-netbsd-64": "0.14.31",
"esbuild-openbsd-64": "0.14.31",
"esbuild-sunos-64": "0.14.31",
"esbuild-windows-32": "0.14.31",
"esbuild-windows-64": "0.14.31",
"esbuild-windows-arm64": "0.14.31"
"@esbuild/android-arm": "0.17.17",
"@esbuild/android-arm64": "0.17.17",
"@esbuild/android-x64": "0.17.17",
"@esbuild/darwin-arm64": "0.17.17",
"@esbuild/darwin-x64": "0.17.17",
"@esbuild/freebsd-arm64": "0.17.17",
"@esbuild/freebsd-x64": "0.17.17",
"@esbuild/linux-arm": "0.17.17",
"@esbuild/linux-arm64": "0.17.17",
"@esbuild/linux-ia32": "0.17.17",
"@esbuild/linux-loong64": "0.17.17",
"@esbuild/linux-mips64el": "0.17.17",
"@esbuild/linux-ppc64": "0.17.17",
"@esbuild/linux-riscv64": "0.17.17",
"@esbuild/linux-s390x": "0.17.17",
"@esbuild/linux-x64": "0.17.17",
"@esbuild/netbsd-x64": "0.17.17",
"@esbuild/openbsd-x64": "0.17.17",
"@esbuild/sunos-x64": "0.17.17",
"@esbuild/win32-arm64": "0.17.17",
"@esbuild/win32-ia32": "0.17.17",
"@esbuild/win32-x64": "0.17.17"
}
},
"esbuild-windows-64": {
"version": "0.14.31",
"dev": true,
"optional": true
},
"escalade": {
"version": "3.1.1"
},
@ -8193,8 +8732,17 @@
"version": "1.0.0",
"dev": true
},
"fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"optional": true
},
"function-bind": {
"version": "1.1.1"
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-caller-file": {
"version": "2.0.5"
@ -8277,6 +8825,8 @@
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"requires": {
"function-bind": "^1.1.1"
}
@ -8409,7 +8959,9 @@
}
},
"is-core-module": {
"version": "2.8.1",
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz",
"integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==",
"requires": {
"has": "^1.0.3"
}
@ -8741,7 +9293,9 @@
"version": "2.0.0"
},
"nanoid": {
"version": "3.3.4",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true
},
"natural-compare": {
@ -8953,6 +9507,8 @@
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"dev": true
},
"picomatch": {
@ -8986,10 +9542,12 @@
"version": "4.0.0"
},
"postcss": {
"version": "8.4.14",
"version": "8.4.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz",
"integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
"dev": true,
"requires": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}
@ -9175,9 +9733,11 @@
}
},
"resolve": {
"version": "1.22.0",
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
"integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
"requires": {
"is-core-module": "^2.8.1",
"is-core-module": "^2.11.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
}
@ -9212,7 +9772,9 @@
}
},
"rollup": {
"version": "2.67.2",
"version": "3.20.6",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.6.tgz",
"integrity": "sha512-2yEB3nQXp/tBQDN0hJScJQheXdvU2wFhh6ld7K/aiZ1vYcak6N/BKjY1QrU6BvO2JWYS8bEs14FRaxXosxy2zw==",
"dev": true,
"requires": {
"fsevents": "~2.3.2"
@ -9333,6 +9895,8 @@
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"dev": true
},
"split2": {
@ -9531,14 +10095,15 @@
"version": "1.1.2"
},
"vite": {
"version": "2.9.6",
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.3.1.tgz",
"integrity": "sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==",
"dev": true,
"requires": {
"esbuild": "^0.14.27",
"esbuild": "^0.17.5",
"fsevents": "~2.3.2",
"postcss": "^8.4.12",
"resolve": "^1.22.0",
"rollup": "^2.59.0"
"postcss": "^8.4.21",
"rollup": "^3.20.2"
}
},
"webidl-conversions": {

View File

@ -14,6 +14,7 @@
"test": "npm run mocha -- test/**/*-tests.js --timeout 15000",
"test-e2e-interactive": "npm run mocha -- test/e2e-tests.js --timeout 15000 --bail --interactive",
"nodemon": "nodemon",
"gulp": "gulp",
"vite": "vite",
"mocha": "mocha",
"eslint": "eslint",
@ -33,7 +34,7 @@
"mocha": "^9.2.1",
"nodemon": "^2.0.15",
"prettier": "^2.8.7",
"vite": "^2.9.6"
"vite": "^4.3.1"
},
"dependencies": {
"@opentelemetry/api": "^1.1.0",

View File

@ -1 +0,0 @@
import 'matrix-public-archive-shared/hydrogen-vm-render-script';

View File

@ -1 +0,0 @@
import 'matrix-public-archive-shared/room-directory-vm-render-script';

View File

@ -2,10 +2,8 @@
const assert = require('assert');
const { getSerializableSpans } = require('../tracing/tracing-middleware');
const renderHydrogenToString = require('../hydrogen-render/render-hydrogen-to-string');
const sanitizeHtml = require('../lib/sanitize-html');
const safeJson = require('../lib/safe-json');
const renderPageHtml = require('../hydrogen-render/render-page-html');
async function renderHydrogenVmRenderScriptToPageHtml({
pageOptions,
@ -15,10 +13,6 @@ async function renderHydrogenVmRenderScriptToPageHtml({
assert(vmRenderScriptFilePath);
assert(vmRenderContext);
assert(pageOptions);
assert(pageOptions.title);
assert(pageOptions.styles);
assert(pageOptions.scripts);
assert(pageOptions.cspNonce);
const hydrogenHtmlOutput = await renderHydrogenToString({
vmRenderScriptFilePath,
@ -26,80 +20,12 @@ async function renderHydrogenVmRenderScriptToPageHtml({
pageOptions,
});
// Serialize the state for when we run the Hydrogen render again client-side to
// re-hydrate the DOM
const serializedMatrixPublicArchiveContext = JSON.stringify({
...vmRenderContext,
const pageHtml = renderPageHtml({
pageOptions,
bodyHtml: hydrogenHtmlOutput,
vmRenderContext,
});
const serializableSpans = getSerializableSpans();
const serializedSpans = JSON.stringify(serializableSpans);
// We shouldn't let some pages be indexed by search engines
let maybeNoIndexHtml = '';
if (!pageOptions.shouldIndex) {
maybeNoIndexHtml = `<meta name="robots" content="noindex, nofollow" />`;
}
const pageHtml = `
<!doctype html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
${maybeNoIndexHtml}
${sanitizeHtml(`<title>${pageOptions.title}</title>`)}
<link rel="icon" href="/img/favicon.ico" sizes="any">
<link rel="icon" href="/img/favicon.svg" type="image/svg+xml">
${pageOptions.styles
.map(
(styleUrl) =>
`<link href="${styleUrl}" rel="stylesheet" nonce="${pageOptions.cspNonce}">`
)
.join('\n')}
</head>
<body>
${hydrogenHtmlOutput}
${
/**
* This inline snippet is used in to scroll the Hydrogen timeline to the
* right place immediately when the page loads instead of waiting for
* Hydrogen to load, hydrate and finally scroll.
*/ ''
}
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
const qs = new URLSearchParams(window?.location?.search);
const atEventId = qs.get('at');
if (atEventId) {
const el = document.querySelector(\`[data-event-id="\${atEventId}"]\`);
requestAnimationFrame(() => {
el && el.scrollIntoView({ block: 'center' });
});
} else {
const el = document.querySelector('.js-bottom-scroll-anchor');
requestAnimationFrame(() => {
el && el.scrollIntoView({ block: 'end' });
});
}
</script>
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
window.matrixPublicArchiveContext = ${safeJson(serializedMatrixPublicArchiveContext)}
</script>
${pageOptions.scripts
.map(
(scriptUrl) =>
`<script type="text/javascript" src="${scriptUrl}" nonce="${pageOptions.cspNonce}"></script>`
)
.join('\n')}
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
window.tracingSpansForRequest = ${safeJson(serializedSpans)};
</script>
</body>
</html>
`;
return pageHtml;
}

View File

@ -0,0 +1,106 @@
'use strict';
const assert = require('assert');
const { getSerializableSpans } = require('../tracing/tracing-middleware');
const sanitizeHtml = require('../lib/sanitize-html');
const safeJson = require('../lib/safe-json');
const getDependenciesForEntryPointName = require('../lib/get-dependencies-for-entry-point-name');
const getFaviconAssetUrls = require('../lib/get-favicon-asset-urls');
const faviconMap = getFaviconAssetUrls();
async function renderPageHtml({
pageOptions,
// Make sure you sanitize this before passing it to us
bodyHtml,
vmRenderContext,
}) {
assert(vmRenderContext);
assert(pageOptions);
assert(pageOptions.title);
assert(pageOptions.entryPoint);
assert(pageOptions.cspNonce);
const { styles, scripts } = getDependenciesForEntryPointName(pageOptions.entryPoint);
console.log('styles', styles);
console.log('scripts', scripts);
// Serialize the state for when we run the Hydrogen render again client-side to
// re-hydrate the DOM
const serializedMatrixPublicArchiveContext = JSON.stringify({
...vmRenderContext,
});
const serializableSpans = getSerializableSpans();
const serializedSpans = JSON.stringify(serializableSpans);
// We shouldn't let some pages be indexed by search engines
let maybeNoIndexHtml = '';
if (!pageOptions.shouldIndex) {
maybeNoIndexHtml = `<meta name="robots" content="noindex, nofollow" />`;
}
const pageHtml = `
<!doctype html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
${maybeNoIndexHtml}
${sanitizeHtml(`<title>${pageOptions.title}</title>`)}
<link rel="icon" href="${faviconMap.ico}" sizes="any">
<link rel="icon" href="${faviconMap.svg}" type="image/svg+xml">
${styles
.map(
(styleUrl) =>
`<link href="${styleUrl}" rel="stylesheet" nonce="${pageOptions.cspNonce}">`
)
.join('\n')}
</head>
<body>
${bodyHtml}
${
/**
* This inline snippet is used in to scroll the Hydrogen timeline to the
* right place immediately when the page loads instead of waiting for
* Hydrogen to load, hydrate and finally scroll.
*/ ''
}
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
const qs = new URLSearchParams(window?.location?.search);
const atEventId = qs.get('at');
if (atEventId) {
const el = document.querySelector(\`[data-event-id="\${atEventId}"]\`);
requestAnimationFrame(() => {
el && el.scrollIntoView({ block: 'center' });
});
} else {
const el = document.querySelector('.js-bottom-scroll-anchor');
requestAnimationFrame(() => {
el && el.scrollIntoView({ block: 'end' });
});
}
</script>
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
window.matrixPublicArchiveContext = ${safeJson(serializedMatrixPublicArchiveContext)}
</script>
${scripts
.map(
(scriptUrl) =>
`<script type="text/javascript" src="${scriptUrl}" nonce="${pageOptions.cspNonce}"></script>`
)
.join('\n')}
<script type="text/javascript" nonce="${pageOptions.cspNonce}">
window.tracingSpansForRequest = ${safeJson(serializedSpans)};
</script>
</body>
</html>
`;
return pageHtml;
}
module.exports = renderPageHtml;

View File

@ -0,0 +1,111 @@
'use strict';
const assert = require('assert');
const path = require('path').posix;
// Lazy-load the manifest so we only require it on first call hopefully after the Vite
// client build completes.
let _manifest;
function getManifest() {
if (_manifest) {
return _manifest;
}
// We have to disable this because it's built via the Vite client build.
// eslint-disable-next-line node/no-missing-require
_manifest = require('../../dist/manifest.json');
return _manifest;
}
let _entryPoints;
function getEntryPoints() {
if (_entryPoints) {
return _entryPoints;
}
const manifest = getManifest();
_entryPoints = Object.keys(manifest).filter((name) => {
return manifest[name].isEntry;
});
return _entryPoints;
}
function recurseManifestEntryName(entryName) {
const manifest = getManifest();
const entry = manifest[entryName];
// css
const styles = [];
// imports
const scripts = [];
// imports, dynamicImports
const preloadScripts = [];
for (const importName of entry.imports || []) {
scripts.push(path.join('/', importName));
preloadScripts.push(path.join('/', importName));
const {
styles: moreStyles,
scripts: moreScripts,
preloadScripts: morePreloadScripts,
} = recurseManifestEntryName(importName);
styles.push(...moreStyles);
scripts.push(...moreScripts);
preloadScripts.push(...morePreloadScripts);
}
for (const dynamicImportName of entry.dynamicImports || []) {
preloadScripts.push(path.join('/', dynamicImportName));
const {
styles: moreStyles,
scripts: moreScripts,
preloadScripts: morePreloadScripts,
} = recurseManifestEntryName(dynamicImportName);
styles.push(...moreStyles);
scripts.push(...moreScripts);
preloadScripts.push(...morePreloadScripts);
}
for (const cssName of entry.css || []) {
styles.push(path.join('/', cssName));
}
return {
// css
styles,
// imports
scripts,
// dynamicImports
preloadScripts,
};
}
// Look through the Vite manifest.json and return the dependencies for a given entry
function getDependenciesForEntryPointName(entryPointName) {
assert(entryPointName);
const manifest = getManifest();
const entry = manifest[entryPointName];
assert(
entry.isEntry,
`You must start with a valid entry point from the Vite manifest.json. Saw ${entryPointName} but the only entry points available are ${JSON.stringify(
getEntryPoints(),
null,
2
)}`
);
const { styles, scripts, preloadScripts } = recurseManifestEntryName(entryPointName);
return {
// De-duplicate assets
styles: Array.from(new Set(styles)),
scripts: Array.from(new Set(scripts)),
preloadScripts: Array.from(new Set(preloadScripts)),
};
}
module.exports = getDependenciesForEntryPointName;

View File

@ -0,0 +1,29 @@
'use strict';
const path = require('path').posix;
// Lazy-load the manifest so we only require it on first call hopefully after the Vite
// client build completes.
let _manifest;
function getManifest() {
if (_manifest) {
return _manifest;
}
// We have to disable this because it's built via the Vite client build.
// eslint-disable-next-line node/no-missing-require
_manifest = require('../../dist/manifest.json');
return _manifest;
}
function getFaviconAssetUrls() {
const manifest = getManifest();
const icoAssetPath = path.join('/', manifest['client/img/favicon.ico'].file);
const svgAssetFile = path.join('/', manifest['client/img/favicon.svg'].file);
return {
ico: icoAssetPath,
svg: svgAssetFile,
};
}
module.exports = getFaviconAssetUrls;

View File

@ -9,18 +9,18 @@ assert(packageInfo.version);
const packageVersion = packageInfo.version;
function readFileSync(path) {
function readVersionFileSync(path) {
try {
return fs.readFileSync(path, 'utf8');
return fs.readFileSync(path, 'utf8').trim();
} catch (err) {
console.warn(`Unable to read version tags path=${path}`, err);
return null;
}
}
const commit = readFileSync(path.join(__dirname, '../../dist/GIT_COMMIT'), 'utf8').trim();
const version = readFileSync(path.join(__dirname, '../../dist/VERSION'), 'utf8').trim();
const versionDate = readFileSync(path.join(__dirname, '../../dist/VERSION_DATE'), 'utf8').trim();
const commit = readVersionFileSync(path.join(__dirname, '../../dist/GIT_COMMIT'), 'utf8');
const version = readVersionFileSync(path.join(__dirname, '../../dist/VERSION'), 'utf8');
const versionDate = readVersionFileSync(path.join(__dirname, '../../dist/VERSION_DATE'), 'utf8');
function getVersionTags() {
return {

View File

@ -2,6 +2,8 @@
const assert = require('assert');
const getDependenciesForEntryPointName = require('../lib/get-dependencies-for-entry-point-name');
// Set some preload link headers which we can use with Cloudflare to turn into 103 early
// hints, https://developers.cloudflare.com/cache/about/early-hints/
//
@ -12,14 +14,15 @@ const assert = require('assert');
function setHeadersToPreloadAssets(res, pageOptions) {
assert(res);
assert(pageOptions);
assert(pageOptions.entryPoint);
const { styles, scripts } = pageOptions;
const { styles, preloadScripts } = getDependenciesForEntryPointName(pageOptions.entryPoint);
const styleLinks = styles.map((styleUrl) => {
return `<${styleUrl}>; rel=preload; as=style`;
});
const scriptLinks = scripts.map((scriptUrl) => {
const scriptLinks = preloadScripts.map((scriptUrl) => {
return `<${scriptUrl}>; rel=preload; as=script`;
});

View File

@ -2,8 +2,8 @@
const assert = require('assert');
const urlJoin = require('url-join');
const safeJson = require('../lib/safe-json');
const sanitizeHtml = require('../lib/sanitize-html');
const renderPageHtml = require('../hydrogen-render/render-page-html');
const config = require('../lib/config');
const basePath = config.get('basePath');
@ -13,47 +13,38 @@ assert(basePath);
// page that will potentially redirect them to the correct place if they tried
// `/r/#room-alias:server/date/2022/10/27` -> `/r/room-alias:server/date/2022/10/27`
function clientSideRoomAliasHashRedirectRoute(req, res) {
const cspNonce = res.locals.cspNonce;
const hydrogenStylesUrl = urlJoin(basePath, '/hydrogen-assets/hydrogen-styles.css');
const stylesUrl = urlJoin(basePath, '/css/styles.css');
const jsBundleUrl = urlJoin(basePath, '/js/entry-client-room-alias-hash-redirect.es.js');
const context = {
config: {
basePath,
},
const pageOptions = {
title: `Page not found - Matrix Public Archive`,
entryPoint: 'client/js/entry-client-room-alias-hash-redirect.js',
locationHref: urlJoin(basePath, req.originalUrl),
// We don't have a Matrix room so we don't know whether or not to index. Just choose
// a safe-default of false.
shouldIndex: false,
cspNonce: res.locals.cspNonce,
};
const serializedContext = JSON.stringify(context);
const pageHtml = `
<!doctype html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page not found - Matrix Public Archive</title>
<link href="${hydrogenStylesUrl}" rel="stylesheet" nonce="${cspNonce}">
<link href="${stylesUrl}" rel="stylesheet" nonce="${cspNonce}">
</head>
${/* We add the .hydrogen class here just to get normal body styles */ ''}
<body class="hydrogen">
<h1>
404: Page not found.
<span class="js-try-redirect-message" style="display: none">One sec while we try to redirect you to the right place.</span>
</h1>
<p>If there was a #room_alias:server hash in the URL, we tried redirecting you to the right place.</p>
<p>
Otherwise, you're simply in a place that does not exist.
You can ${sanitizeHtml(`<a href="${basePath}">go back to the homepage</a>.`)}
</p>
<script type="text/javascript" nonce="${cspNonce}">
window.matrixPublicArchiveContext = ${safeJson(serializedContext)}
</script>
<script type="text/javascript" src="${jsBundleUrl}" nonce="${cspNonce}"></script>
</body>
</html>
const bodyHtml = `
<h1>
404: Page not found.
<span class="js-try-redirect-message" style="display: none">One sec while we try to redirect you to the right place.</span>
</h1>
<p>If there was a #room_alias:server hash in the URL, we tried redirecting you to the right place.</p>
<p>
Otherwise, you're simply in a place that does not exist.
You can ${sanitizeHtml(`<a href="${basePath}">go back to the homepage</a>.`)}
</p>
`;
const pageHtml = renderPageHtml({
pageOptions,
bodyHtml,
vmRenderContext: {
config: {
basePath,
},
},
});
res.status(404);
res.set('Content-Type', 'text/html');
res.send(pageHtml);

View File

@ -38,32 +38,8 @@ function installRoutes(app) {
})
);
// We have to disable no-missing-require lint because it doesn't take into
// account `package.json`. `exports`, see
// https://github.com/mysticatea/eslint-plugin-node/issues/255
app.use(
'/hydrogen-assets',
// eslint-disable-next-line node/no-missing-require
express.static(path.dirname(require.resolve('hydrogen-view-sdk/assets/main.js')))
);
app.get(
// This has to be at the root so that the font URL references resolve correctly
'/hydrogen-assets/hydrogen-styles.css',
asyncHandler(async function (req, res) {
res.set('Content-Type', 'text/css');
// We have to disable no-missing-require lint because it doesn't take into
// account `package.json`. `exports`, see
// https://github.com/mysticatea/eslint-plugin-node/issues/255
// eslint-disable-next-line node/no-missing-require
res.sendFile(require.resolve('hydrogen-view-sdk/assets/theme-element-light.css'));
})
);
// Our own archive app styles and scripts
app.use('/css', express.static(path.join(__dirname, '../../public/css')));
app.use('/img', express.static(path.join(__dirname, '../../public/img')));
app.use('/js', express.static(path.join(__dirname, '../../dist/')));
app.use('/assets', express.static(path.join(__dirname, '../../dist/assets')));
app.use('/', require('./room-directory-routes'));

View File

@ -63,15 +63,9 @@ router.get(
// We index the room directory unless the config says we shouldn't index anything
const shouldIndex = !stopSearchEngineIndexing;
const hydrogenStylesUrl = urlJoin(basePath, '/hydrogen-assets/hydrogen-styles.css');
const stylesUrl = urlJoin(basePath, '/css/styles.css');
const roomDirectoryStylesUrl = urlJoin(basePath, '/css/room-directory.css');
const jsBundleUrl = urlJoin(basePath, '/js/entry-client-room-directory.es.js');
const pageOptions = {
title: `Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl, roomDirectoryStylesUrl],
scripts: [jsBundleUrl],
entryPoint: 'client/js/entry-client-room-directory.js',
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,

View File

@ -870,14 +870,9 @@ router.get(
shouldIndex = roomData?.historyVisibility === `world_readable`;
}
const hydrogenStylesUrl = urlJoin(basePath, '/hydrogen-assets/hydrogen-styles.css');
const stylesUrl = urlJoin(basePath, '/css/styles.css');
const jsBundleUrl = urlJoin(basePath, '/js/entry-client-hydrogen.es.js');
const pageOptions = {
title: `${roomData.name} - Matrix Public Archive`,
styles: [hydrogenStylesUrl, stylesUrl],
scripts: [jsBundleUrl],
entryPoint: 'client/js/entry-client-hydrogen.js',
locationHref: urlJoin(basePath, req.originalUrl),
shouldIndex,
cspNonce: res.locals.cspNonce,

View File

@ -16,12 +16,24 @@ buildClient({
},
});
const nodeArgs = [];
if (process.argv.inspectNode) {
nodeArgs.push('--inspect');
}
if (process.argv.traceWarningsNode) {
nodeArgs.push('--trace-warnings');
}
// Pass through some args
const args = [];
if (process.argv.includes('--tracing')) {
if (process.argv.tracing) {
args.push('--tracing');
}
if (process.argv.logOutputFromChildProcesses) {
args.push('--logOutputFromChildProcesses');
}
// Listen for any changes to files and restart the Node.js server process
//
// For API docs, see
@ -32,6 +44,7 @@ nodemon({
ignoreRoot: ['.git'],
ignore: [path.join(__dirname, '../dist/*')],
args,
nodeArgs,
});
nodemon