Skip to content

Commit

Permalink
Adds JS-only example.
Browse files Browse the repository at this point in the history
Refs #38, #39, #4.

This example application only uses `*.js` source files to validate the use case. It includes JavaScript prerendering code, both in a `prerender_page()` and a standalone `prerender_component()`. It also includes JS client-side scripts and validates that they get included in the final bundle *and* are properly tree shaken when not used.
  • Loading branch information
dgp1130 committed Aug 28, 2021
1 parent d0d58b3 commit 326bea1
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 0 deletions.
34 changes: 34 additions & 0 deletions examples/javascript/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
load("@npm//@bazel/typescript:index.bzl", "ts_library")
load("//:index.bzl", "prerender_pages", "web_resources_devserver")
load("//tools:jasmine.bzl", "jasmine_node_test")

prerender_pages(
name = "page",
src = "page.js",
bundle_css = False, # Optimization: No CSS styling on this page.
lib_deps = ["//packages/rules_prerender"],
deps = ["//examples/javascript/component"],
)

web_resources_devserver(
name = "devserver",
resources = ":page",
)

ts_library(
name = "test_lib",
srcs = ["test.ts"],
testonly = True,
deps = [
"//common:runfiles",
"//common/testing:devserver",
"//common/testing:puppeteer",
"@npm//@types/jasmine",
],
)

jasmine_node_test(
name = "test",
data = [":devserver"],
deps = [":test_lib"],
)
8 changes: 8 additions & 0 deletions examples/javascript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# JavaScript

An example which uses JavaScript source files (as opposed to TypeScript) to
render a component and execute client-side scripts.

This example uses CommonJS to load dependencies, but it should be possible to
use ESM with the right Node version and configuration. Doing so is not fully
tested or supported however.
31 changes: 31 additions & 0 deletions examples/javascript/component/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//:index.bzl", "prerender_component")

prerender_component(
name = "component",
srcs = ["component.js"],
lib_deps = [
":prerender_lib",
"//packages/rules_prerender",
],
scripts = [
":component_script",
":component_script_unused",
],
visibility = ["//examples/javascript:__pkg__"],
)

js_library(
name = "prerender_lib",
srcs = ["prerender_lib.js"],
)

js_library(
name = "component_script",
srcs = ["component_script.js"],
)

js_library(
name = "component_script_unused",
srcs = ["component_script_unused.js"],
)
26 changes: 26 additions & 0 deletions examples/javascript/component/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const { includeScript } = require('rules_prerender');
const { content } = require('rules_prerender/examples/javascript/component/prerender_lib');

/** Renders an example component with a script. */
function renderComponent() {
return `
<div id="component">${content}</div>
<div id="component-replace">
This text to be overwritten by client-side JavaScript.
</div>
${includeScript('rules_prerender/examples/javascript/component/component_script')}
`.trim();
}

/**
* Renders an example component with a script. This is never called and should
* not be seen in the output. Used to validate tree-shaking of JS scripts.
*/
function renderUnused() {
return `
<div>ERROR: Should never be rendered.</div>
${includeScript('rules_prerender/examples/javascript/component/component_script_unused')}
`.trim();
}

module.exports = { renderComponent, renderUnused };
4 changes: 4 additions & 0 deletions examples/javascript/component/component_script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/** @fileoverview Replaces a DOM element at load time. */

const el = document.getElementById('component-replace');
el.innerText = 'This text rendered by component JavaScript!';
8 changes: 8 additions & 0 deletions examples/javascript/component/component_script_unused.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @fileoverview This file should be tree-shaken because the function which
* prerenders this is never called at build time.
*/

// If this is loaded, that's an error, so delete the whole document to fail any
// test which asserts on it.
document.body.innerText = 'Error: Unused script was not tree-shaken.';
5 changes: 5 additions & 0 deletions examples/javascript/component/prerender_lib.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @fileoverview JS file to be used as a dependency of a prerender library. */

const content = 'Hello from a JS component!';

module.exports = { content };
19 changes: 19 additions & 0 deletions examples/javascript/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const { PrerenderResource } = require('rules_prerender');
const { renderComponent } = require('rules_prerender/examples/javascript/component/component');

/* Renders the page. */
module.exports = function*() {
yield PrerenderResource.of('/index.html', `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf8">
<title>JavaScript</title>
</head>
<body>
<h2>JavaScript</h2>
${renderComponent()}
</body>
</html>
`.trim());
}
32 changes: 32 additions & 0 deletions examples/javascript/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'jasmine';

import { resolveRunfile } from 'rules_prerender/common/runfiles';
import { useDevserver } from 'rules_prerender/common/testing/devserver';
import { useBrowser, usePage, puppeteerTestTimeout } from 'rules_prerender/common/testing/puppeteer';

const devserverBinary = resolveRunfile(
'rules_prerender/examples/javascript/devserver');

describe('JavaScript', () => {
const server = useDevserver(devserverBinary);
const browser = useBrowser();
const page = usePage(browser);

it('renders component', async () => {
await page.get().goto(
`http://${server.get().host}:${server.get().port}`,
{ waitUntil: 'load' },
);

const title = await page.get().title();
expect(title).toBe('JavaScript');

const prerendered =
await page.get().$eval('#component', (el) => el.textContent);
expect(prerendered).toBe('Hello from a JS component!');

const replaced = await page.get().$eval(
'#component-replace', (el) => el.textContent);
expect(replaced).toBe('This text rendered by component JavaScript!');
}, puppeteerTestTimeout);
});

0 comments on commit 326bea1

Please sign in to comment.