Merge pull request #448 from vector-im/snowpack-mvp

Snowpack MVP
This commit is contained in:
Bruno Windels 2021-08-18 13:09:02 +00:00 committed by GitHub
commit 02e422f3ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 2453 additions and 64 deletions

View file

@ -10,7 +10,7 @@
"lint": "eslint --cache src/",
"lint-ci": "eslint src/",
"test": "impunity --entry-point src/main.js --force-esm-dirs lib/ src/",
"start": "node scripts/serve-local.js",
"start": "snowpack dev --port 3000",
"build": "node --experimental-modules scripts/build.mjs",
"postinstall": "node ./scripts/post-install.js"
},
@ -39,7 +39,7 @@
"eslint": "^7.25.0",
"fake-indexeddb": "^3.1.2",
"finalhandler": "^1.1.1",
"impunity": "^1.0.0",
"impunity": "^1.0.1",
"mdn-polyfills": "^5.20.0",
"node-html-parser": "^4.0.0",
"postcss": "^8.1.1",
@ -51,6 +51,8 @@
"rollup": "^2.26.4",
"rollup-plugin-cleanup": "^3.1.1",
"serve-static": "^1.13.2",
"snowpack": "^3.8.3",
"typescript": "^4.3.5",
"xxhashjs": "^0.2.2"
},
"dependencies": {

View file

@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {build as snowpackBuild, loadConfiguration} from "snowpack"
import cheerio from "cheerio";
import fsRoot from "fs";
const fs = fsRoot.promises;
@ -45,8 +46,11 @@ import flexbugsFixes from "postcss-flexbugs-fixes";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const projectDir = path.join(__dirname, "../");
const snowpackOutPath = path.join(projectDir, "snowpack-build-output");
const cssSrcDir = path.join(projectDir, "src/platform/web/ui/css/");
const srcDir = path.join(projectDir, "src/");
const snowpackConfig = await loadConfiguration({buildOptions: {out: snowpackOutPath}}, "snowpack.config.js");
const snowpackOutDir = snowpackConfig.buildOptions.out.substring(projectDir.length);
const srcDir = path.join(projectDir, `${snowpackOutDir}/src/`);
const isPathInSrcDir = path => path.startsWith(srcDir);
const parameters = new commander.Command();
@ -56,14 +60,27 @@ parameters
.option("--override-css <main css file>", "pass in an alternative main css file")
parameters.parse(process.argv);
/**
* We use Snowpack to handle the translation of TypeScript
* into JavaScript. We thus can't bundle files straight from
* the src directory, since some of them are TypeScript, and since
* they may import Node modules. We thus bundle files after they
* have been processed by Snowpack. This function returns paths
* to the files that have already been pre-processed in this manner.
*/
function srcPath(src) {
return path.join(snowpackOutDir, 'src', src);
}
async function build({modernOnly, overrideImports, overrideCss}) {
await snowpackBuild({config: snowpackConfig});
// get version number
const version = JSON.parse(await fs.readFile(path.join(projectDir, "package.json"), "utf8")).version;
let importOverridesMap;
if (overrideImports) {
importOverridesMap = await readImportOverrides(overrideImports);
}
const devHtml = await fs.readFile(path.join(projectDir, "index.html"), "utf8");
const devHtml = await fs.readFile(path.join(snowpackOutPath, "index.html"), "utf8");
const doc = cheerio.load(devHtml);
const themes = [];
findThemes(doc, themeName => {
@ -77,13 +94,13 @@ async function build({modernOnly, overrideImports, overrideCss}) {
// copy olm assets
const olmAssets = await copyFolder(path.join(projectDir, "lib/olm/"), assets.directory);
assets.addSubMap(olmAssets);
await assets.write(`hydrogen.js`, await buildJs("src/main.js", ["src/platform/web/Platform.js"], importOverridesMap));
await assets.write(`hydrogen.js`, await buildJs(srcPath("main.js"), [srcPath("platform/web/Platform.js")], importOverridesMap));
if (!modernOnly) {
await assets.write(`hydrogen-legacy.js`, await buildJsLegacy("src/main.js", [
'src/platform/web/legacy-polyfill.js',
'src/platform/web/LegacyPlatform.js'
await assets.write(`hydrogen-legacy.js`, await buildJsLegacy(srcPath("main.js"), [
srcPath('platform/web/legacy-polyfill.js'),
srcPath('platform/web/LegacyPlatform.js')
], importOverridesMap));
await assets.write(`worker.js`, await buildJsLegacy("src/platform/web/worker/main.js", ['src/platform/web/worker/polyfill.js']));
await assets.write(`worker.js`, await buildJsLegacy(srcPath("platform/web/worker/main.js"), [srcPath('platform/web/worker/polyfill.js')]));
}
// copy over non-theme assets
const baseConfig = JSON.parse(await fs.readFile(path.join(projectDir, "assets/config.json"), {encoding: "utf8"}));
@ -97,13 +114,14 @@ async function build({modernOnly, overrideImports, overrideCss}) {
await buildManifest(assets);
// all assets have been added, create a hash from all assets name to cache unhashed files like index.html
assets.addToHashForAll("index.html", devHtml);
let swSource = await fs.readFile(path.join(projectDir, "src/platform/web/service-worker.js"), "utf8");
assets.addToHashForAll("sw.js", swSource);
let swSource = await fs.readFile(path.join(snowpackOutPath, "service-worker.js"), "utf8");
assets.addToHashForAll("service-worker.js", swSource);
const globalHash = assets.hashForAll();
await buildServiceWorker(swSource, version, globalHash, assets);
await buildHtml(doc, version, baseConfig, globalHash, modernOnly, assets);
await removeDirIfExists(snowpackOutPath);
console.log(`built hydrogen ${version} (${globalHash}) successfully with ${assets.size} files`);
}
@ -156,7 +174,7 @@ async function buildHtml(doc, version, baseConfig, globalHash, modernOnly, asset
const configJSON = JSON.stringify(Object.assign({}, baseConfig, {
worker: assets.has("worker.js") ? assets.resolve(`worker.js`) : null,
downloadSandbox: assets.resolve("download-sandbox.html"),
serviceWorker: "sw.js",
serviceWorker: "service-worker.js",
olm: {
wasm: assets.resolve("olm.wasm"),
legacyBundle: assets.resolve("olm_legacy.js"),
@ -324,7 +342,7 @@ async function buildServiceWorker(swSource, version, globalHash, assets) {
swSource = replaceStringInSource("NOTIFICATION_BADGE_ICON", assets.resolve("icon.png"));
// service worker should not have a hashed name as it is polled by the browser for updates
await assets.writeUnhashed("sw.js", swSource);
await assets.writeUnhashed("service-worker.js", swSource);
}
async function buildCssBundles(buildFn, themes, assets, mainCssFile = null) {

View file

@ -75,7 +75,7 @@ async function populateLib() {
const olmDstDir = path.join(libDir, "olm/");
await fs.mkdir(olmDstDir);
for (const file of ["olm.js", "olm.wasm", "olm_legacy.js"]) {
await fs.symlink(path.join(olmSrcDir, file), path.join(olmDstDir, file));
await fs.copyFile(path.join(olmSrcDir, file), path.join(olmDstDir, file));
}
// transpile node-html-parser to esm
await fs.mkdir(path.join(libDir, "node-html-parser/"));
@ -83,12 +83,6 @@ async function populateLib() {
require.resolve('node-html-parser/dist/index.js'),
path.join(libDir, "node-html-parser/index.js")
);
// Symlink dompurify
await fs.mkdir(path.join(libDir, "dompurify/"));
await fs.symlink(
require.resolve('dompurify/dist/purify.es.js'),
path.join(libDir, "dompurify/index.js")
);
// transpile another-json to esm
await fs.mkdir(path.join(libDir, "another-json/"));
await commonjsToESM(

38
snowpack.config.js Normal file
View file

@ -0,0 +1,38 @@
// Snowpack Configuration File
// See all supported options: https://www.snowpack.dev/reference/configuration
/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
// More specific paths before less specific paths (if they overlap)
"src/platform/web/docroot": "/",
"src": "/src",
"lib": {url: "/lib", static: true },
"assets": "/assets",
/* ... */
},
exclude: [
/* Avoid scanning scripts which use dev-dependencies and pull in babel, rollup, etc. */
'**/node_modules/**/*',
'**/scripts/**',
'**/target/**',
'**/prototypes/**',
'**/src/matrix/storage/memory/**',
'**/src/platform/web/legacy-polyfill.js',
'**/src/platform/web/worker/polyfill.js'
],
plugins: [
/* ... */
],
packageOptions: {
/* ... */
},
devOptions: {
open: "none",
hmr: false,
/* ... */
},
buildOptions: {
/* ... */
},
};

View file

@ -18,20 +18,26 @@ limitations under the License.
import {EventKey} from "../EventKey.js";
export const PENDING_FRAGMENT_ID = Number.MAX_SAFE_INTEGER;
interface FragmentIdComparer {
compare: (a: number, b: number) => number
}
export class BaseEntry {
constructor(fragmentIdComparer) {
protected _fragmentIdComparer: FragmentIdComparer
constructor(fragmentIdComparer: FragmentIdComparer) {
this._fragmentIdComparer = fragmentIdComparer;
}
get fragmentId() {
get fragmentId(): number {
throw new Error("unimplemented");
}
get entryIndex() {
get entryIndex(): number {
throw new Error("unimplemented");
}
compare(otherEntry) {
compare(otherEntry: BaseEntry): number {
if (this.fragmentId === otherEntry.fragmentId) {
return this.entryIndex - otherEntry.entryIndex;
} else if (this.fragmentId === PENDING_FRAGMENT_ID) {
@ -44,9 +50,9 @@ export class BaseEntry {
}
}
asEventKey() {
asEventKey(): EventKey {
return new EventKey(this.fragmentId, this.entryIndex);
}
updateFrom() {}
updateFrom(other: BaseEntry) {}
}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseEntry} from "./BaseEntry.js";
import {BaseEntry} from "./BaseEntry";
import {REDACTION_TYPE} from "../../common.js";
import {createAnnotation, ANNOTATION_RELATION_TYPE, getRelationFromContent} from "../relations.js";
import {PendingAnnotation} from "../PendingAnnotation.js";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {BaseEntry} from "./BaseEntry.js";
import {BaseEntry} from "./BaseEntry";
import {Direction} from "../Direction.js";
import {isValidFragmentId} from "../common.js";
import {KeyLimits} from "../../../storage/common.js";

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {PENDING_FRAGMENT_ID} from "./BaseEntry.js";
import {PENDING_FRAGMENT_ID} from "./BaseEntry";
import {BaseEventEntry} from "./BaseEventEntry.js";
export class PendingEventEntry extends BaseEventEntry {

View file

@ -26,7 +26,7 @@
downloadSandbox: "assets/download-sandbox.html",
defaultHomeServer: "matrix.org",
// NOTE: uncomment this if you want the service worker for local development
// serviceWorker: "sw.js",
// serviceWorker: "service-worker.js",
// NOTE: provide push config if you want push notifs for local development
// see assets/config.json for what the config looks like
// push: {...},

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import DOMPurify from "../../../lib/dompurify/index.js"
import DOMPurify from "dompurify"
class HTMLParseResult {
constructor(bodyNode) {

1
sw.js
View file

@ -1 +0,0 @@
src/platform/web/service-worker.js

8
tsconfig.json Normal file
View file

@ -0,0 +1,8 @@
{
"compilerOptions": {
"strictNullChecks": true,
"noEmit": true,
"target": "es6"
},
"include": ["src/**/*"],
}

2388
yarn.lock

File diff suppressed because it is too large Load diff