From d1b5567007acb141435d9a82969b2785c1461cfd Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 13:44:23 +0530 Subject: [PATCH 1/8] feat: Added Support For URL Parameters for A/B Testing. --- index.js | 19 ++++++++++--------- utils/normalizeRspOptions.js | 1 + 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/index.js b/index.js index 5b8e180..74c9c09 100644 --- a/index.js +++ b/index.js @@ -28,7 +28,7 @@ async function readOptionsFromFile() { * @param {string} dir * @returns {string|boolean} */ -async function runStaticServer(port, routes, dir) { +async function runStaticServer(port, routes, params, dir) { try { app = express(); const resolvedPath = resolve(dir); @@ -41,7 +41,7 @@ async function runStaticServer(port, routes, dir) { await app.listen(port); return `http://localhost:${port}`; - } catch(err) { + } catch (err) { throw new Error(`Error: Failed to run puppeteer server on port ${port}.\nMessage: ${err}`); } } @@ -61,7 +61,7 @@ async function createNewHTMLPage(route, html, dir) { const fileName = getValidatedFileName(route); - await fs.writeFileSync(`${dir}${fileName}`, html, {encoding: 'utf-8', flag: 'w'}); + await fs.writeFileSync(`${dir}${fileName}`, html, { encoding: 'utf-8', flag: 'w' }); console.log(`Created ${fileName}`); } catch (err) { throw new Error(`Error: Failed to create HTML page for ${route}.\nMessage: ${err}`); @@ -78,13 +78,13 @@ async function getHTMLfromPuppeteerPage(browser, pageUrl, options) { try { const page = await browser.newPage(); - await page.goto(pageUrl, Object.assign({waitUntil: 'networkidle0'}, options)); + await page.goto(pageUrl, Object.assign({ waitUntil: 'networkidle0' }, options)); const html = await page.content(); if (!html) return 0; return html; - } catch(err) { + } catch (err) { throw new Error(`Error: Failed to build HTML for ${pageUrl}.\nMessage: ${err}`); } } @@ -96,12 +96,13 @@ async function getHTMLfromPuppeteerPage(browser, pageUrl, options) { * @param {object} engine * @returns {number|undefined} */ -async function runPuppeteer(baseUrl, routes, dir, engine) { +async function runPuppeteer(baseUrl, routes, params, dir, engine) { const browser = await puppeteer.launch(engine.launchOptions); for (let i = 0; i < routes.length; i++) { try { console.log(`Processing route "${routes[i]}"`); - const html = await getHTMLfromPuppeteerPage(browser, `${baseUrl}${routes[i]}`, engine.gotoOptions); + const parameters = params[i] || ""; + const html = await getHTMLfromPuppeteerPage(browser, `${baseUrl}${routes[i]}${parameters}`, engine.gotoOptions); if (html) createNewHTMLPage(routes[i], html, dir); else return 0; } catch (err) { @@ -115,11 +116,11 @@ async function runPuppeteer(baseUrl, routes, dir, engine) { async function run(config) { const options = config || await readOptionsFromFile(); - const staticServerURL = await runStaticServer(options.port, options.routes, options.buildDirectory); + const staticServerURL = await runStaticServer(options.port, options.routes, options.urlParameter, options.buildDirectory); if (!staticServerURL) return 0; - await runPuppeteer(staticServerURL, options.routes, options.buildDirectory, options.engine); + await runPuppeteer(staticServerURL, options.routes, options.urlParameter, options.buildDirectory, options.engine); console.log('Finish react-spa-prerender tasks!'); process.exit(); } diff --git a/utils/normalizeRspOptions.js b/utils/normalizeRspOptions.js index 9b9ff06..76a321e 100644 --- a/utils/normalizeRspOptions.js +++ b/utils/normalizeRspOptions.js @@ -11,6 +11,7 @@ module.exports = function (options) { return { routes: options.routes || [], + urlParameter: options.urlParameter || [], port: options.port || 3000, buildDirectory: options.buildDirectory || './build', engine From 390a77d5fd64b77483367cbe537d2d66b58c26ca Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 13:49:22 +0530 Subject: [PATCH 2/8] update: Bumped Version to Alpha2. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 190679d..1185284 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-spa-prerender", - "version": "1.0.14", + "version": "1.0.15.alpha2", "description": "React library for prerendering static pages, optimize SEO and web performance", "main": "index.js", "scripts": { From 1b8a59a28b9804a85bab1ac3586e20e4c1aa79fb Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 13:53:09 +0530 Subject: [PATCH 3/8] fix: Incorrect Package Name. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1185284..56817b9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-spa-prerender", - "version": "1.0.15.alpha2", + "version": "1.0.15", "description": "React library for prerendering static pages, optimize SEO and web performance", "main": "index.js", "scripts": { From 1079385b801378b194962d36b7c15c18e0edf612 Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 14:22:28 +0530 Subject: [PATCH 4/8] update: URL Parameter Options in Document. --- README.md | 56 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 4d4d795..c891380 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,36 @@ # react-spa-prerender + The easiest way to prerender static pages, optimize SEO and build high performance for your React SPA. Build production-ready code just by adding few lines of code. -* [Example of usage with create-react-app](https://github.com/sPavl0v/react-spa-prenderer/tree/master/examples/cra) -* [create-react-app + lazy loading](https://github.com/sPavl0v/react-spa-prenderer/tree/master/examples/cra-lazy) + +- [Example of usage with create-react-app](https://github.com/sPavl0v/react-spa-prenderer/tree/master/examples/cra) +- [create-react-app + lazy loading](https://github.com/sPavl0v/react-spa-prenderer/tree/master/examples/cra-lazy) ### Upcoming features -* Auto sitemap generation -* Prebuilding pages with dynamic routes + +- Auto sitemap generation +- Prebuilding pages with dynamic routes Follow the steps below: ## Install + With npm + ``` npm install react-spa-prerender --save-dev ``` + With yarn + ``` yarn add react-spa-prerender --dev ``` ## Add as postbuild script + In your package.json add the following in the scripts section: + ``` "scripts": { "postbuild": "react-spa-prerender", @@ -29,9 +38,11 @@ In your package.json add the following in the scripts section: ``` ## Add .rsp.json file -__.rsp.json__ is the configuration file for `react-spa-prerender`. Create this file in your __application root folder__. -The minimum configuration requires the __routes__ you want to be parsed. + +**.rsp.json** is the configuration file for `react-spa-prerender`. Create this file in your **application root folder**. +The minimum configuration requires the **routes** you want to be parsed. Example: + ``` { routes: [ @@ -43,6 +54,7 @@ Example: ] } ``` + From example above: Your "/" route will transform into "index.html" page. "/about" -> "about.html" @@ -50,17 +62,21 @@ Your "/" route will transform into "index.html" page. "/blog/article1" -> create blog directory with file "article1.html" ("/blog/article1.html") and so on... -__The rest of the .rsp.json options described below__ +**The rest of the .rsp.json options described below** ## Add ReactDOM.hydrate in your index.js + In your index.js(main app file) change the ReactDOM.render logic: + ``` import ReactDOM from 'react-dom'; const rootElement = document.getElementById("root"); ReactDOM.render(, rootElement); ``` + Into following: + ``` import ReactDOM from 'react-dom'; @@ -74,24 +90,26 @@ if (rootElement.hasChildNodes()) { ``` ## Voila!!! + That's it. After accomplishing all the steps above, run you build command and your prerendered files will be in your build directory. ## .rsp.json Options -|option | type | default | description | -|-----|--------|------|---------| -| routes(Required) | Array | - | An array of routes you want to parse and prerender into static html| -| port | Number | 3000 | port where prerendering server will be starting | -| buildDirectory | String | './build' | a relative path to your build folder -|engine | Object | {} | params for Puppeteer engine, list of available params described below - +| option | type | default | description | +| ---------------------- | ------ | --------- | --------------------------------------------------------------------- | +| routes(Required) | Array | - | An array of routes you want to parse and prerender into static html | +| urlParameter(Optional) | Array | - | An array of URL Parameter you want to pass along with Route | +| port | Number | 3000 | port where prerendering server will be starting | +| buildDirectory | String | './build' | a relative path to your build folder | +| engine | Object | {} | params for Puppeteer engine, list of available params described below | ### Engine options: + - launchOptions - object, containing properties to control **puppeteer.launch()** command. The whole list of available properties available here: [https://pptr.dev/#?product=Puppeteer&version=v10.0.0&show=api-puppeteerlaunchoptions](https://pptr.dev/#?product=Puppeteer&version=v10.0.0&show=api-puppeteerlaunchoptions) - gotoOptions - object, navigation parameters. The whole list of available properties available here: [https://pptr.dev/#?product=Puppeteer&version=v10.0.0&show=api-pagegotourl-options](https://pptr.dev/#?product=Puppeteer&version=v10.0.0&show=api-pagegotourl-options) - #### Example of .rsp.json with engine options: + ``` { "port": 3000, @@ -113,6 +131,12 @@ That's it. After accomplishing all the steps above, run you build command and yo "/services", "/blog/article1", "/blog/article2" + ], + "urlParameter": [ + "?type=a", + "?type=b", + "", + "?demo=yes" ] } -``` \ No newline at end of file +``` From 51cc34e5a0f1cafaea4fc3ef99034aa0549a4abd Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 15:00:01 +0530 Subject: [PATCH 5/8] docs: Added Multi Parameter Example. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c891380..bd7c020 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ That's it. After accomplishing all the steps above, run you build command and yo "?type=a", "?type=b", "", - "?demo=yes" + "?demo=yes&tester=yes" ] } ``` From 6e21072b199ce2292ec400480b8d0c0edc73add4 Mon Sep 17 00:00:00 2001 From: Kewal Rathod <43823249+Kewal89@users.noreply.github.com> Date: Sat, 19 Nov 2022 15:01:39 +0530 Subject: [PATCH 6/8] feat: Exception for Incorrect URL Parameters. --- index.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 74c9c09..c3abf3d 100644 --- a/index.js +++ b/index.js @@ -96,17 +96,19 @@ async function getHTMLfromPuppeteerPage(browser, pageUrl, options) { * @param {object} engine * @returns {number|undefined} */ -async function runPuppeteer(baseUrl, routes, params, dir, engine) { + async function runPuppeteer(baseUrl, routes, params, dir, engine) { const browser = await puppeteer.launch(engine.launchOptions); for (let i = 0; i < routes.length; i++) { + const parameters = params[i] || ""; + console.log(`Processing route "${routes[i]}${parameters}"`); + if (parameters && !parameters.startsWith("?")) throw new Error(`Error: Failed to process parameters "${routes[i]}${parameters}"\nMessage: URL Parameters can be blank or must start with "?"`); + try { - console.log(`Processing route "${routes[i]}"`); - const parameters = params[i] || ""; const html = await getHTMLfromPuppeteerPage(browser, `${baseUrl}${routes[i]}${parameters}`, engine.gotoOptions); if (html) createNewHTMLPage(routes[i], html, dir); else return 0; } catch (err) { - throw new Error(`Error: Failed to process route "${routes[i]}"\nMessage: ${err}`); + throw new Error(`Error: Failed to process route "${routes[i]}${parameters}"\nMessage: ${err}`); } } From 0be62c33d549d50b315a4e361aa99d84a2525eb7 Mon Sep 17 00:00:00 2001 From: Kewal Rathod Date: Sat, 7 Jan 2023 15:14:06 +0530 Subject: [PATCH 7/8] BREAKING CHANGE: Updated prop name to "urlParameters" * Added Additional 's' to maintain naming convention. --- README.md | 4 ++-- index.js | 4 ++-- utils/normalizeRspOptions.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bd7c020..2a71a2b 100644 --- a/README.md +++ b/README.md @@ -98,7 +98,7 @@ That's it. After accomplishing all the steps above, run you build command and yo | option | type | default | description | | ---------------------- | ------ | --------- | --------------------------------------------------------------------- | | routes(Required) | Array | - | An array of routes you want to parse and prerender into static html | -| urlParameter(Optional) | Array | - | An array of URL Parameter you want to pass along with Route | +| urlParameters(Optional) | Array | - | An array of URL Parameter you want to pass along with Route | | port | Number | 3000 | port where prerendering server will be starting | | buildDirectory | String | './build' | a relative path to your build folder | | engine | Object | {} | params for Puppeteer engine, list of available params described below | @@ -132,7 +132,7 @@ That's it. After accomplishing all the steps above, run you build command and yo "/blog/article1", "/blog/article2" ], - "urlParameter": [ + "urlParameters": [ "?type=a", "?type=b", "", diff --git a/index.js b/index.js index c3abf3d..f961289 100644 --- a/index.js +++ b/index.js @@ -118,11 +118,11 @@ async function getHTMLfromPuppeteerPage(browser, pageUrl, options) { async function run(config) { const options = config || await readOptionsFromFile(); - const staticServerURL = await runStaticServer(options.port, options.routes, options.urlParameter, options.buildDirectory); + const staticServerURL = await runStaticServer(options.port, options.routes, options.urlParameters, options.buildDirectory); if (!staticServerURL) return 0; - await runPuppeteer(staticServerURL, options.routes, options.urlParameter, options.buildDirectory, options.engine); + await runPuppeteer(staticServerURL, options.routes, options.urlParameters, options.buildDirectory, options.engine); console.log('Finish react-spa-prerender tasks!'); process.exit(); } diff --git a/utils/normalizeRspOptions.js b/utils/normalizeRspOptions.js index 76a321e..b7f61ae 100644 --- a/utils/normalizeRspOptions.js +++ b/utils/normalizeRspOptions.js @@ -11,7 +11,7 @@ module.exports = function (options) { return { routes: options.routes || [], - urlParameter: options.urlParameter || [], + urlParameters: options.urlParameters || [], port: options.port || 3000, buildDirectory: options.buildDirectory || './build', engine From 95521f19f85921b3561a7720ba2d30f884aac073 Mon Sep 17 00:00:00 2001 From: Kewal Rathod Date: Sat, 7 Jan 2023 15:16:15 +0530 Subject: [PATCH 8/8] docs: Reformatted README.md. --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2a71a2b..3ca9d94 100644 --- a/README.md +++ b/README.md @@ -95,13 +95,13 @@ That's it. After accomplishing all the steps above, run you build command and yo ## .rsp.json Options -| option | type | default | description | -| ---------------------- | ------ | --------- | --------------------------------------------------------------------- | -| routes(Required) | Array | - | An array of routes you want to parse and prerender into static html | +| option | type | default | description | +| ----------------------- | ------ | --------- | --------------------------------------------------------------------- | +| routes(Required) | Array | - | An array of routes you want to parse and prerender into static html | | urlParameters(Optional) | Array | - | An array of URL Parameter you want to pass along with Route | -| port | Number | 3000 | port where prerendering server will be starting | -| buildDirectory | String | './build' | a relative path to your build folder | -| engine | Object | {} | params for Puppeteer engine, list of available params described below | +| port | Number | 3000 | port where prerendering server will be starting | +| buildDirectory | String | './build' | a relative path to your build folder | +| engine | Object | {} | params for Puppeteer engine, list of available params described below | ### Engine options: