Skip to content

Commit

Permalink
isolate embed config into separate package
Browse files Browse the repository at this point in the history
This allows us to not include all of coral-common into
the embed.js, reducing its bundle size down to ~30 KB as
it has been for the last few years.

Now, we get both the benefits of a shared common/ lib as
well as all the small embed size benefits.
  • Loading branch information
nick-funk committed Jul 27, 2023
1 parent 31a33c6 commit 52d02d8
Show file tree
Hide file tree
Showing 21 changed files with 600 additions and 124 deletions.
5 changes: 5 additions & 0 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ cd server
npm run generate
cd ..

echo "running \`npm run build\` for \`config\`"
cd config
npm run build
cd ..

echo "running \`npm run build\` for \`common\`"
cd common
npm run build
Expand Down
9 changes: 9 additions & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"license": "Apache-2.0",
"dependencies": {
"coral-common": "../common/dist",
"coral-config": "../config/dist",
"@ampproject/toolbox-cache-url": "^2.9.0",
"@coralproject/bunyan-prettystream": "^0.1.4",
"@fluent/bundle": "^0.15.1",
Expand Down Expand Up @@ -450,7 +451,7 @@
"bundlesize": [
{
"path": "./dist/static/assets/js/embed.js",
"maxSize": "30 kB",
"maxSize": "30.05 kB",
"maxSizeOld": "17 kB"
},
{
Expand Down
4 changes: 2 additions & 2 deletions client/src/core/client/embed/Coral.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { EventEmitter2 } from "eventemitter2";
import { parse } from "querystringify";

import { parseQuery } from "coral-common/common/lib/utils";
import { getCurrentScriptOrigin } from "coral-framework/helpers";
import resolveStoryURL from "coral-framework/helpers/resolveStoryURL";

Expand Down Expand Up @@ -43,7 +43,7 @@ export interface Config {

export function createStreamEmbed(config: Config): StreamEmbed {
// Parse query params
const query = parseQuery(location.search);
const query = parse(location.search);
const embedEventEmitter = new EventEmitter2({
wildcard: true,
delimiter: ".",
Expand Down
10 changes: 8 additions & 2 deletions client/src/core/client/embed/StreamEmbed.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { EmbedBootstrapConfig } from "coral-common/common/lib/config";
import ensureEndSlash from "coral-common/common/lib/utils/ensureEndSlash";
import { EmbedBootstrapConfig } from "coral-config/config";
import { getBrowserInfo } from "coral-framework/lib/browserInfo";
import { EventEmitter2 } from "eventemitter2";

Expand Down Expand Up @@ -31,6 +30,12 @@ const LOAD_BOOTSTRAP_RETRY_DELAY = 2000;
const LOAD_BOOTSTRAP_RETRY_DELAY_MULTIPLIER =
process.env.NODE_ENV === "production" ? 2000 : 0;

const END_SLASH_REGEX = /\/$/;

export default function ensureEndSlash(p: string) {
return END_SLASH_REGEX.exec(p) ? p : `${p}/`;
}

export interface StreamEmbedConfig {
storyID?: string;
storyURL?: string;
Expand All @@ -51,6 +56,7 @@ export interface StreamEmbedConfig {
graphQLSubscriptionURI?: string;
customScrollContainer?: HTMLElement;
}

export class StreamEmbed {
/**
* Every interval rounded to this value in ms will be passed when loading
Expand Down
5 changes: 4 additions & 1 deletion client/src/core/client/embed/decorators/withEventEmitter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { EventEmitter2 } from "eventemitter2";

import startsWith from "coral-common/common/lib/utils/startsWith";
/** A substitute for string.startsWith */
function startsWith(str: string, search: string, pos?: number) {
return str.substr(!pos || pos < 0 ? 0 : +pos, search.length) === search;
}

const withEventEmitter = (
streamEventEmitter: EventEmitter2,
Expand Down
31 changes: 28 additions & 3 deletions client/src/core/client/embed/decorators/withSetCommentID.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
import { EventEmitter2 } from "eventemitter2";
import qs, { parse } from "querystringify";

import { parseQuery, stringifyQuery } from "coral-common/common/lib/utils";
import { buildURL } from "coral-framework/utils";

import { CleanupCallback } from "./types";

/**
* From the `querystringify` project:
* This transforms a given object in to a query string.
* By default we return the query string without a ? prefix.
* If you want to prefix it by default simply supply true as second argument.
* If it should be prefixed by something else simply supply a string with the
* prefix value as second argument.
*
* In addition keys that have an undefined value are removed from the query.
*/
function stringifyQuery(
obj: Record<string, any>,
prefix?: string | boolean
): string {
const copy: Record<string, any> = {};
Object.keys(obj).forEach((key) => {
if (obj[key] === undefined) {
return;
}

copy[key] = obj[key];
});
return qs.stringify(copy, prefix);
}

function getCurrentCommentID() {
return parseQuery(location.search).commentID;
return parse(location.search).commentID;
}

const withSetCommentID = (
Expand All @@ -15,7 +40,7 @@ const withSetCommentID = (
// Add the permalink comment id to the query.
streamEventEmitter.on("stream.setCommentID", (id: string) => {
const search = stringifyQuery({
...parseQuery(location.search),
...parse(location.search),
commentID: id || undefined,
});

Expand Down
97 changes: 10 additions & 87 deletions common/lib/config.ts
Original file line number Diff line number Diff line change
@@ -1,91 +1,14 @@
import { LanguageCode } from "./helpers";
import {
EmbedBootstrapConfig as EBC,
ReporterConfig as RC,
SentryReporterConfig as SRC,
StaticConfig as SC,
} from "coral-config/config";

/**
* SentryReporterConfig is the ReporterConfig for the Sentry service.
*/
export interface SentryReporterConfig {
name: "sentry";
export interface SentryReporterConfig extends SRC {}

/**
* dsn is the string representing this particular integration.
*/
dsn: string;
}
export type ReporterConfig = RC;

export type ReporterConfig = SentryReporterConfig;
export interface StaticConfig extends SC {}

/**
* StaticConfig is the configuration provided to the client javascript via a
* JSON blob on the HTML of the embedding page.
*/
export interface StaticConfig {
/**
* staticURI is prepended to the static url's that are included on the static
* pages.
*/
staticURI: string;

/**
* tenantDomain is the domain of the currently requested tenant.
*/
tenantDomain?: string;

/**
* reporter stores the reporter configuration for the current reporter
* available.
*/
reporter?: ReporterConfig;

/**
* graphQLSubscriptionURI is the endpoint that should be used when trying to
* execute subscription GraphQL requests. If an empty string, the default
* should be used that's based on the iFrame location.
*/
graphQLSubscriptionURI: string;

/**
* featureFlags are all the feature flags currently enabled on the tenant.
*/
featureFlags: string[];

/**
* flattenReplies is whether or not flattenReplies is enabled on the tenant.
*/
flattenReplies: boolean;

/**
* forceAdminLocalAuth is whether local authentication is always available
* for this Coral deployment. This is useful for ensuring that Coral service
* teams can access the admin with their Coral local authentication.
*/
forceAdminLocalAuth: boolean;

/**
* archivingEnabled will be true when the deployment has set a valid MongoDB
* URI for MONGODB_ARCHIVE_URI.
*/
archivingEnabled: boolean;

/**
* autoArchiveOlderThanMs is the time in milliseconds that a story will
* be kept before being auto-archived.
*/
autoArchiveOlderThanMs: number;
}

export interface EmbedBootstrapConfig {
locale: LanguageCode;
assets: {
js: {
src: string;
}[];
css: {
src: string;
}[];
};
customFontsCSSURL: string | undefined;
customCSSURL: string | undefined;
defaultFontsCSSURL: string | undefined;
disableDefaultFonts: boolean;
staticConfig: StaticConfig;
}
export interface EmbedBootstrapConfig extends EBC {}
27 changes: 3 additions & 24 deletions common/lib/helpers/i18n/locales.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,10 @@
import { LanguageCode as LC } from "coral-config/i18n/locales";

/**
* LanguageCode is the type represented by the internally identifiable types for
* the different languages that can be supported in the BCP 47 format.
*/
export type LanguageCode =
| "af-ZA"
| "ar-AE"
| "en-US"
| "pt-BR"
| "es"
| "de"
| "tr-TR"
| "hu"
| "id-ID"
| "it-IT"
| "ja-JP"
| "de-CH"
| "nl-NL"
| "da"
| "fr-FR"
| "ro"
| "fi-FI"
| "sv"
| "sk-SK"
| "pl"
| "ru"
| "nb-NO"
| "zh-CN";
export type LanguageCode = LC;

/**
* LOCALES_MAP contains a map of language codes associated with their
Expand Down
9 changes: 9 additions & 0 deletions common/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@types/url-regex-safe": "^1.0.0"
},
"dependencies": {
"coral-config": "../config/dist",
"dompurify": "^2.0.17",
"he": "^1.2.0",
"jest": "^26.4.2",
Expand Down
5 changes: 5 additions & 0 deletions config/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*.d.ts
*.graphql.ts
**/__generated__/**
docs/build
docs/.docusaurus
Loading

0 comments on commit 52d02d8

Please sign in to comment.