Reworking static page generation
Including styles in components wasn't working with the old system.
This commit is contained in:
parent
ad6583d5dc
commit
7238643740
2
.babelrc
2
.babelrc
@ -1,4 +1,4 @@
|
||||
{
|
||||
"presets": ["env", "react"],
|
||||
"plugins": ["transform-class-properties"]
|
||||
"plugins": ["transform-class-properties", "syntax-dynamic-import"]
|
||||
}
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,6 +20,7 @@ node_modules/
|
||||
|
||||
# Build output
|
||||
build/
|
||||
prerender/
|
||||
|
||||
# Coverage reports
|
||||
coverage/
|
||||
|
@ -13,7 +13,9 @@
|
||||
"start": "webpack-dev-server --config webpack.dev.js",
|
||||
"start:prod": "run-s build start:http-server",
|
||||
"start:http-server": "http-server ./build",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"build": "run-s build:webpack build:prerender",
|
||||
"build:webpack": "webpack --config webpack.prod.js",
|
||||
"build:prerender": "node ./prerender/prerender.js",
|
||||
"test": "run-s test:lint 'test:unit --coverage'",
|
||||
"test:unit": "jest",
|
||||
"test:lint": "eslint --ignore-path .gitignore .",
|
||||
@ -49,10 +51,12 @@
|
||||
"babel-eslint": "^8.2.1",
|
||||
"babel-jest": "^22.2.2",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-syntax-dynamic-import": "^6.18.0",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-register": "^6.26.0",
|
||||
"cheerio": "^1.0.0-rc.2",
|
||||
"copy-webpack-plugin": "^4.4.1",
|
||||
"css-loader": "^0.28.9",
|
||||
"enzyme": "^3.3.0",
|
||||
@ -82,6 +86,7 @@
|
||||
"uglifyjs-webpack-plugin": "^1.1.8",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-merge": "^4.1.1",
|
||||
"webpack-node-externals": "^1.6.0",
|
||||
"workbox-webpack-plugin": "^2.1.2",
|
||||
"yaml-loader": "^0.5.0"
|
||||
},
|
||||
|
@ -1,15 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
import Header from './Header';
|
||||
import Footer from './Footer';
|
||||
import Message from './Message';
|
||||
|
||||
const App = () => <React.Fragment>
|
||||
<Header/>
|
||||
const App = () => (
|
||||
<Message heading="React App">
|
||||
<p>Placeholder app content</p>
|
||||
</Message>
|
||||
<Footer/>
|
||||
</React.Fragment>;
|
||||
);
|
||||
|
||||
export default App;
|
||||
|
@ -1,13 +0,0 @@
|
||||
import 'babel-register';
|
||||
import React from 'react';
|
||||
|
||||
import '../../i18n';
|
||||
|
||||
import PageTemplate, { renderToString } from '../../components/PageTemplate';
|
||||
import Component from './Component';
|
||||
|
||||
export default renderToString(
|
||||
<PageTemplate>
|
||||
<Component/>
|
||||
</PageTemplate>
|
||||
);
|
@ -1,16 +1,13 @@
|
||||
import 'babel-register';
|
||||
import React from 'react';
|
||||
|
||||
import '../../i18n';
|
||||
|
||||
import PageTemplate, { renderToString } from '../../components/PageTemplate';
|
||||
import Message from '../../components/Message';
|
||||
import AlertIcon from 'feather-icons/dist/icons/alert-octagon.svg';
|
||||
import Header from '../../components/Header';
|
||||
import Footer from '../../components/Footer';
|
||||
import App from '../../components/App';
|
||||
|
||||
export default renderToString(
|
||||
<PageTemplate>
|
||||
const Component = () => (
|
||||
<React.Fragment>
|
||||
<Header/>
|
||||
<noscript>
|
||||
<Message className="error" icon={ AlertIcon } heading="JavaScript Required">
|
||||
@ -23,6 +20,9 @@ export default renderToString(
|
||||
<p>Most popular ad blockers will prevent these tools from sending any tracking data, and doing so will <b>not</b> impact the performance of this app. Regexper is not supported by ad revenue or sales of any kind. The information collected by these tools is used to monitor application performance, determine browser support, and collect error reports.</p>
|
||||
</Message>
|
||||
</noscript>
|
||||
<App/>
|
||||
<Footer/>
|
||||
</PageTemplate>
|
||||
</React.Fragment>
|
||||
);
|
||||
|
||||
export default Component;
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import App from '../../components/App';
|
||||
import Component from './Component';
|
||||
import RavenBoundary from '../../components/RavenBoundary';
|
||||
|
||||
import '../../style.css';
|
||||
@ -20,7 +20,7 @@ try {
|
||||
|
||||
ReactDOM.render(
|
||||
<RavenBoundary>
|
||||
<App/>
|
||||
<Component/>
|
||||
</RavenBoundary>,
|
||||
document.getElementById('root'));
|
||||
}
|
20
src/prerender.js
Normal file
20
src/prerender.js
Normal file
@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import { renderToString } from 'react-dom/server';
|
||||
import fs from 'fs';
|
||||
import cheerio from 'cheerio';
|
||||
|
||||
import './i18n';
|
||||
|
||||
const pages = fs.readdirSync('./src/pages');
|
||||
|
||||
pages.forEach(page => {
|
||||
import(`./pages/${ page }/Component`).then(component => {
|
||||
const Component = component.default;
|
||||
const pagePath = `./build/${ page }.html`;
|
||||
|
||||
const markup = cheerio.load(fs.readFileSync(pagePath));
|
||||
|
||||
markup('#root').html(renderToString(<Component/>));
|
||||
fs.writeFileSync(pagePath, markup.html());
|
||||
});
|
||||
});
|
15
src/template.html
Normal file
15
src/template.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||
<meta name="description" content={ pkg.description } />
|
||||
|
||||
<link rel="author" href="/humans.txt" />
|
||||
|
||||
<title>Regexper</title>
|
||||
</head>
|
||||
<body data-build-id="<%= process.env.BUILD_ID %>">
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>
|
@ -10,7 +10,7 @@ const pkg = require('./package.json');
|
||||
|
||||
const pages = fs.readdirSync(path.resolve(__dirname, 'src/pages'));
|
||||
const pagePlugins = pages.map(name => new HtmlPlugin({
|
||||
template: `./src/pages/${ name }/template.js`,
|
||||
template: './src/template.html',
|
||||
filename: `${ name }.html`,
|
||||
chunks: ['common', name],
|
||||
minify: {
|
||||
@ -28,7 +28,7 @@ const pagePlugins = pages.map(name => new HtmlPlugin({
|
||||
|
||||
module.exports = {
|
||||
entry: pages.reduce((pages, name) => {
|
||||
pages[name] = `./src/pages/${ name }`;
|
||||
pages[name] = `./src/pages/${ name }/browser`;
|
||||
return pages;
|
||||
}, {}),
|
||||
output: {
|
||||
|
@ -1,17 +1,52 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const common = require('./webpack.common.js');
|
||||
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
|
||||
const WorkboxPlugin = require('workbox-webpack-plugin');
|
||||
const nodeExternals = require('webpack-node-externals');
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new UglifyJSPlugin({
|
||||
sourceMap: true
|
||||
}),
|
||||
new WorkboxPlugin({
|
||||
clientsClaim: true,
|
||||
skipWaiting: true
|
||||
})
|
||||
]
|
||||
});
|
||||
module.exports = [
|
||||
// Web
|
||||
merge(common, {
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new UglifyJSPlugin({
|
||||
sourceMap: true
|
||||
}),
|
||||
new WorkboxPlugin({
|
||||
clientsClaim: true,
|
||||
skipWaiting: true
|
||||
})
|
||||
]
|
||||
}),
|
||||
// Node (prerender)
|
||||
{
|
||||
target: 'node',
|
||||
externals: [nodeExternals({
|
||||
whitelist: [ /\.svg$/ ]
|
||||
})],
|
||||
entry: {
|
||||
prerender: './src/prerender.js'
|
||||
},
|
||||
output: {
|
||||
filename: '[name].js',
|
||||
chunkFilename: '[name].chunk.js',
|
||||
path: path.resolve(__dirname, 'prerender')
|
||||
},
|
||||
plugins: [
|
||||
// Only want the EnvironmentPlugin
|
||||
common.plugins.find(plugin => plugin instanceof webpack.EnvironmentPlugin)
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
// Replace the rule for CSS files
|
||||
{
|
||||
test: /\.css$/,
|
||||
loader: 'css-loader/locals'
|
||||
},
|
||||
...common.module.rules.filter(rule => !rule.oneOf)
|
||||
]
|
||||
}
|
||||
}
|
||||
];
|
||||
|
@ -619,6 +619,10 @@ babel-plugin-syntax-class-properties@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
|
||||
|
||||
babel-plugin-syntax-dynamic-import@^6.18.0:
|
||||
version "6.18.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
|
||||
|
||||
babel-plugin-syntax-exponentiation-operator@^6.8.0:
|
||||
version "6.13.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de"
|
||||
@ -8200,6 +8204,10 @@ webpack-merge@^4.1.1:
|
||||
dependencies:
|
||||
lodash "^4.17.4"
|
||||
|
||||
webpack-node-externals@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.6.0.tgz#232c62ec6092b100635a3d29d83c1747128df9bd"
|
||||
|
||||
webpack-sources@^1.0.1, webpack-sources@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.1.0.tgz#a101ebae59d6507354d71d8013950a3a8b7a5a54"
|
||||
|
Loading…
Reference in New Issue
Block a user