Inline scripts in HTML files
This commit is contained in:
@ -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 = '<!DOCTYPE html>';
|
||||
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);
|
||||
|
@ -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 = '<!DOCTYPE html>';
|
||||
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);
|
||||
|
71
modules/actions/utils/MainTemplate.js
Normal file
71
modules/actions/utils/MainTemplate.js
Normal file
@ -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)
|
||||
};
|
||||
}
|
1
modules/actions/utils/createElement.js
Normal file
1
modules/actions/utils/createElement.js
Normal file
@ -0,0 +1 @@
|
||||
export { createElement as default } from 'react';
|
3
modules/actions/utils/createHTML.js
Normal file
3
modules/actions/utils/createHTML.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default function createHTML(code) {
|
||||
return { __html: code };
|
||||
}
|
8
modules/actions/utils/createScript.js
Normal file
8
modules/actions/utils/createScript.js
Normal file
@ -0,0 +1,8 @@
|
||||
import createElement from './createElement';
|
||||
import createHTML from './createHTML';
|
||||
|
||||
export default function createScript(script) {
|
||||
return createElement('script', {
|
||||
dangerouslySetInnerHTML: createHTML(script)
|
||||
});
|
||||
}
|
17
modules/actions/utils/getEntryPoint.js
Normal file
17
modules/actions/utils/getEntryPoint.js
Normal file
@ -0,0 +1,17 @@
|
||||
// Virtual module id; see rollup.config.js
|
||||
import entryManifest from 'entry-manifest';
|
||||
|
||||
export default function getEntryPoint(name, format) {
|
||||
let entryPoints;
|
||||
entryManifest.forEach(manifest => {
|
||||
if (name in manifest) {
|
||||
entryPoints = manifest[name];
|
||||
}
|
||||
});
|
||||
|
||||
if (entryPoints) {
|
||||
return entryPoints.find(e => e.format === format);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
10
modules/actions/utils/getGlobalScripts.js
Normal file
10
modules/actions/utils/getGlobalScripts.js
Normal file
@ -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] });
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user