Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/issue 954 puppeteer plugin #960

Merged
merged 23 commits into from
Jul 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b717fdf
puppeteer renderer plugin and migrate resource plugin
thescientist13 Jul 3, 2022
dfe99b4
introduce custom function option for renderer plugins and moved puppe…
thescientist13 Jul 9, 2022
1d2d62b
made WCC default prerender
thescientist13 Jul 9, 2022
f862855
stabilize specs
thescientist13 Jul 9, 2022
ad6095d
upgrade latest version of puppeteer
thescientist13 Jul 9, 2022
f835cfc
add specs for puppeteer renderer plugin
thescientist13 Jul 9, 2022
2f469c1
clarify it block
thescientist13 Jul 10, 2022
e67cbdc
stablize all CLI specs
thescientist13 Jul 10, 2022
6a787d7
fix spelling mistake
thescientist13 Jul 10, 2022
53c76ba
comments for init specs
thescientist13 Jul 10, 2022
6c33f1f
restore graphql specs with dependency on puppeteer plugin when preren…
thescientist13 Jul 10, 2022
32b7da7
restore all specs and adjust thresholds
thescientist13 Jul 10, 2022
bd4f957
misc PR cleanup
thescientist13 Jul 10, 2022
506da03
fix lint and clean up package jsons
thescientist13 Jul 10, 2022
d03cd59
fix lint and clean up package jsons
thescientist13 Jul 11, 2022
f3e229c
upgrade latest version of WCC
thescientist13 Jul 12, 2022
fc78d5e
update docs to reflect prerendering with WCC and cross dependencies w…
thescientist13 Jul 13, 2022
9338bf2
fix and restore puppeteer based inline javascript execution specs
thescientist13 Jul 13, 2022
7afcc8a
fix typo in specs
thescientist13 Jul 13, 2022
1ddb1e5
Merge branch 'feature/issue-954-puppeteer-plugin' of github.com:Proje…
thescientist13 Jul 13, 2022
76a4f2f
cross platform puppeteer intercepting support
thescientist13 Jul 13, 2022
462fdf2
refactor preRenderCompilationWorker to be async Promise.all
thescientist13 Jul 13, 2022
92ada60
Merge branch 'feature/issue-954-puppeteer-plugin' of github.com:Proje…
thescientist13 Jul 13, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .c8rc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

"statements": 80,
"branches": 85,
"functions": 90,
"functions": 85,
"lines": 80,

"watermarks": {
Expand Down
4 changes: 3 additions & 1 deletion greenwood.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { greenwoodPluginImportCss } from '@greenwood/plugin-import-css';
import { greenwoodPluginImportJson } from '@greenwood/plugin-import-json';
import { greenwoodPluginPolyfills } from '@greenwood/plugin-polyfills';
import { greenwoodPluginPostCss } from '@greenwood/plugin-postcss';
import { greenwoodPluginRendererPuppeteer } from '@greenwood/plugin-renderer-puppeteer';
import rollupPluginAnalyzer from 'rollup-plugin-analyzer';
import { fileURLToPath, URL } from 'url';

Expand Down Expand Up @@ -33,7 +34,8 @@ export default {
];
}
},
...greenwoodPluginIncludeHTML()
...greenwoodPluginIncludeHTML(),
...greenwoodPluginRendererPuppeteer()
],
markdown: {
plugins: [
Expand Down
12 changes: 1 addition & 11 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,9 @@
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"puppeteer": "^13.5.2"
},
"peerDependenciesMeta": {
"puppeteer": {
"optional": true
}
},
"dependencies": {
"@rollup/plugin-node-resolve": "^13.0.0",
"@rollup/plugin-replace": "^2.3.4",
"@webcomponents/webcomponentsjs": "^2.6.0",
"acorn": "^8.0.1",
"acorn-walk": "^8.0.0",
"commander": "^2.20.0",
Expand All @@ -56,7 +47,7 @@
"rollup": "^2.58.0",
"rollup-plugin-terser": "^7.0.0",
"unified": "^9.2.0",
"wc-compiler": "~0.3.1"
"wc-compiler": "~0.4.0"
},
"devDependencies": {
"@babel/runtime": "^7.10.4",
Expand All @@ -70,7 +61,6 @@
"lit-redux-router": "~0.20.0",
"lodash-es": "^4.17.20",
"postcss-nested": "^4.1.2",
"puppeteer": "^13.5.2",
"pwa-helpers": "^0.9.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
Expand Down
66 changes: 31 additions & 35 deletions packages/cli/src/commands/build.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { bundleCompilation } from '../lifecycles/bundle.js';
import { copyAssets } from '../lifecycles/copy.js';
import { getDevServer } from '../lifecycles/serve.js';
import fs from 'fs';
import { preRenderCompilationCustom, preRenderCompilationDefault, staticRenderCompilation } from '../lifecycles/prerender.js';
import { preRenderCompilationWorker, preRenderCompilationCustom, staticRenderCompilation } from '../lifecycles/prerender.js';
import { ServerInterface } from '../lib/server-interface.js';

const runProductionBuild = async (compilation) => {
Expand All @@ -11,8 +10,10 @@ const runProductionBuild = async (compilation) => {

try {
const { prerender } = compilation.config;
const port = compilation.config.devServer.port;
const outputDir = compilation.context.outputDir;
const defaultPrerender = (compilation.config.plugins.filter(plugin => plugin.type === 'renderer' && plugin.isGreenwoodDefaultPlugin) || []).length === 1
? compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation)
: {};
const customPrerender = (compilation.config.plugins.filter(plugin => plugin.type === 'renderer' && !plugin.isGreenwoodDefaultPlugin) || []).length === 1
? compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation)
: {};
Expand All @@ -22,45 +23,40 @@ const runProductionBuild = async (compilation) => {
}

if (prerender || customPrerender.prerender) {
if (customPrerender.prerender) {
// start any servers if needed
const servers = [...compilation.config.plugins.filter((plugin) => {
return plugin.type === 'server';
}).map((plugin) => {
const provider = plugin.provider(compilation);

if (!(provider instanceof ServerInterface)) {
console.warn(`WARNING: ${plugin.name}'s provider is not an instance of ServerInterface.`);
}

return provider;
})];

await Promise.all(servers.map(async (server) => {
await server.start();

return Promise.resolve(server);
}));

if (customPrerender.workerUrl) {
await preRenderCompilationWorker(compilation, customPrerender);
} else if (customPrerender.customUrl) {
await preRenderCompilationCustom(compilation, customPrerender);
} else if (defaultPrerender && prerender) {
await preRenderCompilationWorker(compilation, defaultPrerender);
} else {
await new Promise(async (resolve, reject) => {
try {
(await getDevServer(compilation)).listen(port, async () => {
console.info(`Started prerender server at localhost:${port}`);

const servers = [...compilation.config.plugins.filter((plugin) => {
return plugin.type === 'server';
}).map((plugin) => {
const provider = plugin.provider(compilation);

if (!(provider instanceof ServerInterface)) {
console.warn(`WARNING: ${plugin.name}'s provider is not an instance of ServerInterface.`);
}

return provider;
})];

await Promise.all(servers.map(async (server) => {
server.start();

return Promise.resolve(server);
}));

await preRenderCompilationDefault(compilation);

resolve();
});
} catch (e) {
reject(e);
}
});
reject('This is an unhandled pre-rendering case! Please report.');
}
} else {
await staticRenderCompilation(compilation);
}

console.info('success, done generating all pages!');

await bundleCompilation(compilation);
await copyAssets(compilation);

Expand Down
37 changes: 0 additions & 37 deletions packages/cli/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ process.setMaxListeners(0);

import { generateCompilation } from './lifecycles/compile.js';
import fs from 'fs';
import path from 'path';
import program from 'commander';
import { URL } from 'url';

Expand Down Expand Up @@ -60,40 +59,6 @@ if (program.parse.length === 0) {
program.help();
}

// auto install puppeteer if user has enabled prerendering and not installed it already
async function checkForPuppeteer(compilation) {
if (compilation.config.prerender && !fs.existsSync(path.join(process.cwd(), '/node_modules/puppeteer'))) {
const puppeteerVersion = greenwoodPackageJson.peerDependencies.puppeteer;
console.log('prerender configuration detected but puppeteer is not detected.');
console.log(`attempting to auto-install puppeteer@${puppeteerVersion} ...`);

try {
await new Promise(async (resolve, reject) => {
const os = await import('os');
const spawn = (await import('child_process')).spawn;
const pkgMng = fs.existsSync(path.join(process.cwd(), 'yarn.lock')) ? 'yarn' : 'npm';
const command = pkgMng === 'yarn' ? 'add' : 'install';
const commandFlags = pkgMng === 'yarn' ? '--dev' : '--save-dev';
const pkgCommand = os.platform() === 'win32' ? `${pkgMng}.cmd` : pkgMng;
const args = [command, `puppeteer@${puppeteerVersion}`, commandFlags];
const childProcess = spawn(pkgCommand, args, { stdio: 'ignore' });

childProcess.on('close', code => {
if (code !== 0) {
reject();
return;
}
console.log('auto installation successful!');
resolve();
});
});
} catch (e) {
console.error(`Sorry, we were unable to auto-install puppeteer@${puppeteerVersion}.`);
console.log('Please visit our website for more information on self-installation: https://www.greenwoodjs.io/docs/configuration/#prerender');
}
}
}

const run = async() => {
const compilation = await generateCompilation();

Expand All @@ -104,7 +69,6 @@ const run = async() => {
switch (command) {

case 'build':
await checkForPuppeteer(compilation);
await (await import('./commands/build.js')).runProductionBuild(compilation);

break;
Expand All @@ -115,7 +79,6 @@ const run = async() => {
case 'serve':
process.env.__GWD_COMMAND__ = 'build';

await checkForPuppeteer(compilation);
await (await import('./commands/build.js')).runProductionBuild(Object.assign({}, compilation));
await (await import('./commands/serve.js')).runProdServer(compilation);

Expand Down
44 changes: 26 additions & 18 deletions packages/cli/src/lib/ssr-route-worker.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
// https://github.com/nodejs/modules/issues/307#issuecomment-858729422
import { pathToFileURL } from 'url';
import { workerData, parentPort } from 'worker_threads';
import { renderToString } from 'wc-compiler';
import { renderToString, renderFromHTML } from 'wc-compiler';

async function executeRouteModule({ modulePath, compilation, route, label, id }) {
const moduleURL = pathToFileURL(modulePath);
const module = await import(moduleURL).then(module => module);
const { getFrontmatter = null, getBody = null, getTemplate = null } = module;
async function executeRouteModule({ modulePath, compilation, route, label, id, prerender, htmlContents, scripts }) {
const parsedCompilation = JSON.parse(compilation);
const data = {
template: null,
body: null,
frontmatter: null
frontmatter: null,
html: null
};

if (getFrontmatter) {
data.frontmatter = await getFrontmatter(parsedCompilation, route, label, id);
}
if (prerender) {
const scriptURLs = JSON.parse(scripts).map(scriptFile => new URL(scriptFile));
const { html } = await renderFromHTML(htmlContents, scriptURLs);

if (getTemplate) {
data.template = await getTemplate(parsedCompilation, route);
}
data.html = html;
} else {
const module = await import(pathToFileURL(modulePath)).then(module => module);
const { getTemplate = null, getBody = null, getFrontmatter = null } = module;

if (module.default) {
const { html } = await renderToString(moduleURL);
if (module.default) {
const { html } = await renderToString(pathToFileURL(modulePath));

data.body = html;
} else {
if (getBody) {
data.body = await getBody(parsedCompilation, route);
data.body = html;
} else {
if (getBody) {
data.body = await getBody(parsedCompilation, route);
}
}

if (getTemplate) {
data.template = await getTemplate(parsedCompilation, route);
}

if (getFrontmatter) {
data.frontmatter = await getFrontmatter(parsedCompilation, route, label, id);
}
}

Expand Down
Loading