From ea85062ff62dae46cddc23e468f34338b89b4261 Mon Sep 17 00:00:00 2001 From: Michael Jackson Date: Thu, 24 Jan 2019 15:49:21 -0800 Subject: [PATCH] Inline scripts in HTML files --- modules/actions/serveAutoIndexPage.js | 44 ++-- modules/actions/serveMainPage.js | 29 ++- modules/actions/utils/MainTemplate.js | 71 ++++++ modules/actions/utils/createElement.js | 1 + .../{client => actions}/utils/createHTML.js | 0 modules/actions/utils/createScript.js | 8 + modules/{ => actions}/utils/getEntryPoint.js | 0 modules/actions/utils/getGlobalScripts.js | 10 + modules/client/MainTemplate.js | 68 ------ modules/client/utils/execScript.js | 7 - modules/utils/getScripts.js | 16 -- modules/utils/renderTemplate.js | 11 - package-lock.json | 208 ++++++++++++++++++ package.json | 1 + plugins/entryManifest.js | 3 +- rollup.config.js | 9 +- 16 files changed, 350 insertions(+), 136 deletions(-) create mode 100644 modules/actions/utils/MainTemplate.js create mode 100644 modules/actions/utils/createElement.js rename modules/{client => actions}/utils/createHTML.js (100%) create mode 100644 modules/actions/utils/createScript.js rename modules/{ => actions}/utils/getEntryPoint.js (100%) create mode 100644 modules/actions/utils/getGlobalScripts.js delete mode 100644 modules/client/MainTemplate.js delete mode 100644 modules/client/utils/execScript.js delete mode 100644 modules/utils/getScripts.js delete mode 100644 modules/utils/renderTemplate.js diff --git a/modules/actions/serveAutoIndexPage.js b/modules/actions/serveAutoIndexPage.js index 81c13cb..83cf873 100644 --- a/modules/actions/serveAutoIndexPage.js +++ b/modules/actions/serveAutoIndexPage.js @@ -1,13 +1,16 @@ -import React from 'react'; -import ReactDOMServer from 'react-dom/server'; +import { renderToString, renderToStaticMarkup } from 'react-dom/server'; import semver from 'semver'; -import MainTemplate from '../client/MainTemplate'; import AutoIndexApp from '../client/autoIndex/App'; -import createHTML from '../client/utils/createHTML'; -import getScripts from '../utils/getScripts'; -import renderTemplate from '../utils/renderTemplate'; +import createElement from './utils/createElement'; +import createHTML from './utils/createHTML'; +import createScript from './utils/createScript'; +import getEntryPoint from './utils/getEntryPoint'; +import getGlobalScripts from './utils/getGlobalScripts'; +import MainTemplate from './utils/MainTemplate'; + +const doctype = ''; const globalURLs = process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging' ? { @@ -34,24 +37,27 @@ export default function serveAutoIndexPage(req, res) { entry: req.entry, entries: req.entries }; - - const content = createHTML( - ReactDOMServer.renderToString(React.createElement(AutoIndexApp, data)) + const content = createHTML(renderToString(createElement(AutoIndexApp, data))); + const entryPoint = getEntryPoint('autoIndex', 'iife'); + const elements = getGlobalScripts(entryPoint, globalURLs).concat( + createScript(entryPoint.code) ); - const scripts = getScripts('autoIndex', globalURLs); - - const html = renderTemplate(MainTemplate, { - title: `UNPKG - ${req.packageName}`, - description: `The CDN for ${req.packageName}`, - data, - content, - scripts - }); + const html = + doctype + + renderToStaticMarkup( + createElement(MainTemplate, { + title: `UNPKG - ${req.packageName}`, + description: `The CDN for ${req.packageName}`, + data, + content, + elements + }) + ); res .set({ - 'Cache-Control': 'no-cache, no-store, must-revalidate', // do not cache + 'Cache-Control': 'public, max-age=14400', // 4 hours 'Cache-Tag': 'auto-index' }) .send(html); diff --git a/modules/actions/serveMainPage.js b/modules/actions/serveMainPage.js index 9061cba..6e3bfc4 100644 --- a/modules/actions/serveMainPage.js +++ b/modules/actions/serveMainPage.js @@ -1,12 +1,15 @@ -import React from 'react'; -import { renderToString } from 'react-dom/server'; +import { renderToString, renderToStaticMarkup } from 'react-dom/server'; -import MainTemplate from '../client/MainTemplate'; import MainApp from '../client/main/App'; -import createHTML from '../client/utils/createHTML'; -import getScripts from '../utils/getScripts'; -import renderTemplate from '../utils/renderTemplate'; +import createElement from './utils/createElement'; +import createHTML from './utils/createHTML'; +import createScript from './utils/createScript'; +import getEntryPoint from './utils/getEntryPoint'; +import getGlobalScripts from './utils/getGlobalScripts'; +import MainTemplate from './utils/MainTemplate'; + +const doctype = ''; const globalURLs = process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging' ? { @@ -21,13 +24,19 @@ const globalURLs = }; export default function serveMainPage(req, res) { - const content = createHTML(renderToString(React.createElement(MainApp))); - const scripts = getScripts('main', globalURLs); - const html = renderTemplate(MainTemplate, { content, scripts }); + const content = createHTML(renderToString(createElement(MainApp))); + const entryPoint = getEntryPoint('main', 'iife'); + const elements = getGlobalScripts(entryPoint, globalURLs).concat( + createScript(entryPoint.code) + ); + + const html = + doctype + + renderToStaticMarkup(createElement(MainTemplate, { content, elements })); res .set({ - 'Cache-Control': 'no-cache, no-store, must-revalidate', // do not cache + 'Cache-Control': 'public, max-age=14400', // 4 hours 'Cache-Tag': 'main' }) .send(html); diff --git a/modules/actions/utils/MainTemplate.js b/modules/actions/utils/MainTemplate.js new file mode 100644 index 0000000..cd5bafc --- /dev/null +++ b/modules/actions/utils/MainTemplate.js @@ -0,0 +1,71 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import e from './createElement'; +import h from './createHTML'; +import x from './createScript'; + +const promiseShim = + 'window.Promise || document.write(\'\\x3Cscript src="/es6-promise@4.2.5/dist/es6-promise.min.js">\\x3C/script>\\x3Cscript>ES6Promise.polyfill()\\x3C/script>\')'; +const fetchShim = + 'window.fetch || document.write(\'\\x3Cscript src="/whatwg-fetch@3.0.0/dist/fetch.umd.js">\\x3C/script>\')'; + +export default function MainTemplate({ + title, + description, + favicon, + data, + content, + elements +}) { + return e( + 'html', + { lang: 'en' }, + e( + 'head', + null, + e('meta', { charSet: 'utf-8' }), + e('meta', { httpEquiv: 'X-UA-Compatible', content: 'IE=edge,chrome=1' }), + description && e('meta', { name: 'description', content: description }), + e('meta', { + name: 'viewport', + content: 'width=device-width,initial-scale=1,maximum-scale=1' + }), + e('meta', { name: 'timestamp', content: new Date().toISOString() }), + favicon && e('link', { rel: 'shortcut icon', href: favicon }), + e('title', null, title), + x(promiseShim), + x(fetchShim), + data && x(`window.__DATA__ = ${JSON.stringify(data)}`) + ), + e( + 'body', + null, + e('div', { id: 'root', dangerouslySetInnerHTML: content }), + ...elements + ) + ); +} + +MainTemplate.defaultProps = { + title: 'UNPKG', + description: 'The CDN for everything on npm', + favicon: '/favicon.ico', + content: h(''), + elements: [] +}; + +if (process.env.NODE_ENV !== 'production') { + const htmlType = PropTypes.shape({ + __html: PropTypes.string + }); + + MainTemplate.propTypes = { + title: PropTypes.string, + description: PropTypes.string, + favicon: PropTypes.string, + data: PropTypes.any, + content: htmlType, + elements: PropTypes.arrayOf(PropTypes.node) + }; +} diff --git a/modules/actions/utils/createElement.js b/modules/actions/utils/createElement.js new file mode 100644 index 0000000..a617356 --- /dev/null +++ b/modules/actions/utils/createElement.js @@ -0,0 +1 @@ +export { createElement as default } from 'react'; diff --git a/modules/client/utils/createHTML.js b/modules/actions/utils/createHTML.js similarity index 100% rename from modules/client/utils/createHTML.js rename to modules/actions/utils/createHTML.js diff --git a/modules/actions/utils/createScript.js b/modules/actions/utils/createScript.js new file mode 100644 index 0000000..6bd3ab9 --- /dev/null +++ b/modules/actions/utils/createScript.js @@ -0,0 +1,8 @@ +import createElement from './createElement'; +import createHTML from './createHTML'; + +export default function createScript(script) { + return createElement('script', { + dangerouslySetInnerHTML: createHTML(script) + }); +} diff --git a/modules/utils/getEntryPoint.js b/modules/actions/utils/getEntryPoint.js similarity index 100% rename from modules/utils/getEntryPoint.js rename to modules/actions/utils/getEntryPoint.js diff --git a/modules/actions/utils/getGlobalScripts.js b/modules/actions/utils/getGlobalScripts.js new file mode 100644 index 0000000..cdb3fa0 --- /dev/null +++ b/modules/actions/utils/getGlobalScripts.js @@ -0,0 +1,10 @@ +import invariant from 'invariant'; + +import createElement from './createElement'; + +export default function getGlobalScripts(entryPoint, globalURLs) { + return entryPoint.globalImports.map(id => { + invariant(globalURLs[id], 'Missing global URL for id "%s"', id); + return createElement('script', { src: globalURLs[id] }); + }); +} diff --git a/modules/client/MainTemplate.js b/modules/client/MainTemplate.js deleted file mode 100644 index 3697eef..0000000 --- a/modules/client/MainTemplate.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import createHTML from './utils/createHTML'; -import x from './utils/execScript'; - -const promiseShim = - 'window.Promise || document.write(\'\\x3Cscript src="/es6-promise@4.2.5/dist/es6-promise.min.js">\\x3C/script>\\x3Cscript>ES6Promise.polyfill()\\x3C/script>\')'; -const fetchShim = - 'window.fetch || document.write(\'\\x3Cscript src="/whatwg-fetch@3.0.0/dist/fetch.umd.js">\\x3C/script>\')'; - -export default function MainTemplate({ - title, - description, - favicon, - data, - content, - scripts -}) { - return ( - - - - - {description && } - - - {favicon && } - {title} - {x(promiseShim)} - {x(fetchShim)} - {data && x(`window.__DATA__ = ${JSON.stringify(data)}`)} - - -
- {scripts.map(src => ( -