Skip to content

Commit

Permalink
Chore: Updating html-webpack-plugin to v4 (#1608)
Browse files Browse the repository at this point in the history
  • Loading branch information
rschristian committed Jul 7, 2022
1 parent 3f389c2 commit 90d4596
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 885 deletions.
6 changes: 6 additions & 0 deletions .changeset/rude-walls-dress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'preact-cli': minor
'@preact/prerender-data-provider': patch
---

Updates to use html-webpack-plugin v4
110 changes: 62 additions & 48 deletions packages/cli/lib/lib/webpack/render-html-plugin.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const { resolve, join } = require('path');
const os = require('os');
const { existsSync, readFileSync, writeFileSync, mkdirSync } = require('fs');
const HtmlWebpackExcludeAssetsPlugin = require('html-webpack-exclude-assets-plugin');
const {
HtmlWebpackSkipAssetsPlugin,
} = require('html-webpack-skip-assets-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const prerender = require('./prerender');
const createLoadManifest = require('./create-load-manifest');
Expand All @@ -15,8 +17,8 @@ function read(path) {
return readFileSync(resolve(__dirname, path), 'utf-8');
}

module.exports = async function (config) {
const { cwd, dest, isProd, src } = config;
module.exports = async function renderHTMLPlugin(config) {
const { cwd, dest, src } = config;
const inProjectTemplatePath = resolve(src, 'template.html');
let template = defaultTemplate;
if (existsSync(inProjectTemplatePath)) {
Expand All @@ -32,14 +34,11 @@ module.exports = async function (config) {
}

let content = read(template);
if (/preact\.headEnd|preact\.bodyEnd/.test(content)) {
if (/preact\.(title|headEnd|bodyEnd)/.test(content)) {
const headEnd = read('../../resources/head-end.ejs');
const bodyEnd = read('../../resources/body-end.ejs');
content = content
.replace(
/<%[=]?\s+preact\.title\s+%>/,
'<%= htmlWebpackPlugin.options.title %>'
)
.replace(/<%[=]?\s+preact\.title\s+%>/, '<%= cli.title %>')
.replace(/<%\s+preact\.headEnd\s+%>/, headEnd)
.replace(/<%\s+preact\.bodyEnd\s+%>/, bodyEnd);

Expand All @@ -54,53 +53,69 @@ module.exports = async function (config) {
}

const htmlWebpackConfig = values => {
const { url, title, ...routeData } = values;
let { url, title, ...routeData } = values;

title =
title ||
config.title ||
config.manifest.name ||
config.manifest.short_name ||
(config.pkg.name || '').replace(/^@[a-z]\//, '') ||
'Preact App';

// Do not create a folder if the url is for a specific file.
const filename = url.endsWith('.html')
? resolve(dest, url.substring(1))
: resolve(dest, url.substring(1), 'index.html');
return Object.assign(values, {

return {
title,
filename,
template: `!!${require.resolve('ejs-loader')}?esModule=false!${template}`,
minify: isProd && {
collapseWhitespace: true,
removeScriptTypeAttributes: true,
removeRedundantAttributes: true,
removeStyleLinkTypeAttributes: true,
removeComments: true,
templateParameters: (compilation, assets, assetTags, options) => {
let entrypoints = {};
compilation.entrypoints.forEach((entrypoint, name) => {
let entryFiles = entrypoint.getFiles();
entrypoints[name] =
assets.publicPath +
entryFiles.find(file => /\.(m?js)(\?|$)/.test(file));
});

let loadManifest = compilation.assets['push-manifest.json']
? JSON.parse(compilation.assets['push-manifest.json'].source())
: createLoadManifest(
compilation.assets,
compilation.namedChunkGroups
);

return {
cli: {
title,
url,
manifest: config.manifest,
inlineCss: config['inline-css'],
preload: config.preload,
config,
preRenderData: values,
CLI_DATA: { preRenderData: { url, ...routeData } },
ssr: config.prerender ? prerender({ cwd, dest, src }, values) : '',
loadManifest,
entrypoints,
},
htmlWebpackPlugin: {
tags: assetTags,
files: assets,
options,
},
};
},
inject: true,
scriptLoading: 'defer',
favicon: existsSync(resolve(src, 'assets/favicon.ico'))
? 'assets/favicon.ico'
: '',
inject: true,
compile: true,
inlineCss: config['inline-css'],
preload: config.preload,
manifest: config.manifest,
title:
title ||
config.title ||
config.manifest.name ||
config.manifest.short_name ||
(config.pkg.name || '').replace(/^@[a-z]\//, '') ||
'Preact App',
excludeAssets: [/(bundle|polyfills)(\..*)?\.js$/],
createLoadManifest: (assets, namedChunkGroups) => {
if (assets['push-manifest.json']) {
return JSON.parse(assets['push-manifest.json'].source());
}
return createLoadManifest(assets, namedChunkGroups);
},
config,
url,
ssr() {
return config.prerender && url !== PREACT_FALLBACK_URL
? prerender({ cwd, dest, src }, values)
: '';
},
scriptLoading: 'defer',
CLI_DATA: { preRenderData: { url, ...routeData } },
});
};
};

let pages = [{ url: '/' }];
Expand Down Expand Up @@ -151,7 +166,7 @@ module.exports = async function (config) {
const resultPages = pages
.map(htmlWebpackConfig)
.map(conf => new HtmlWebpackPlugin(conf))
.concat([new HtmlWebpackExcludeAssetsPlugin()]);
.concat([new HtmlWebpackSkipAssetsPlugin()]);

return config.prerender
? resultPages.concat([
Expand All @@ -163,10 +178,9 @@ module.exports = async function (config) {
// Adds a preact_prerender_data in every folder so that the data could be fetched separately.
class PrerenderDataExtractPlugin {
constructor(page) {
const cliData = page.CLI_DATA || {};
const { url } = cliData.preRenderData || {};
const url = page.url;
this.location_ = url.endsWith('/') ? url : url + '/';
this.data_ = JSON.stringify(cliData.preRenderData || {});
this.data_ = JSON.stringify(page || {});
}
apply(compiler) {
compiler.hooks.emit.tap('PrerenderDataExtractPlugin', compilation => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/lib/lib/webpack/webpack-client-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ function isProd(env) {
preload: 'media',
pruneSource: false,
logLevel: 'silent',
additionalStylesheets: ['*.css'],
additionalStylesheets: ['route-*.css'],
})
);
}
Expand Down
18 changes: 9 additions & 9 deletions packages/cli/lib/resources/body-end.ejs
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<%= htmlWebpackPlugin.options.ssr() %>
<% if (htmlWebpackPlugin.options.config.prerender === true) { %>
<%= cli.ssr %>
<% if (cli.config.prerender === true) { %>
<script type="__PREACT_CLI_DATA__">
<%= encodeURI(JSON.stringify(htmlWebpackPlugin.options.CLI_DATA)) %>
<%= encodeURI(JSON.stringify(cli.CLI_DATA)) %>
</script>
<% } %>
<% if (webpack.assets.filter(entry => entry.name.match(/bundle(\.\w{5})?.esm.js$/)).length > 0) { %>
<script crossorigin="anonymous" src="<%= htmlWebpackPlugin.files.publicPath %><%= webpack.assets.filter(entry => entry.name.match(/bundle(\.\w{5})?.esm.js$/))[0].name %>" type="module"></script>
<% if (htmlWebpackPlugin.files.js.filter(entry => entry.match(/bundle(\.\w{5})?.esm.js$/)).length > 0) { %>
<script crossorigin="anonymous" src="<%= htmlWebpackPlugin.files.js.filter(entry => entry.match(/bundle(\.\w{5})?.esm.js$/))[0] %>" type="module"></script>
<%
/*Fetch and Promise polyfills are not needed for browsers that support type=module
Please re-evaluate below line if adding more polyfills.*/
%>
<script nomodule src="<%= htmlWebpackPlugin.files.chunks["polyfills"].entry %>"></script>
<script nomodule defer src="<%= htmlWebpackPlugin.files.chunks['bundle'].entry %>"></script>
<script nomodule src="<%= cli.entrypoints['polyfills'] %>"></script>
<script nomodule defer src="<%= cli.entrypoints['bundle'] %>"></script>
<% } else { %>
<script <%= htmlWebpackPlugin.options.scriptLoading %> src="<%= htmlWebpackPlugin.files.chunks['bundle'].entry %>"></script>
<script nomodule src="<%= htmlWebpackPlugin.files.chunks["polyfills"].entry %>"></script>
<script <%= htmlWebpackPlugin.options.scriptLoading %> src="<%= cli.entrypoints['bundle'] %>"></script>
<script nomodule src="<%= cli.entrypoints['polyfills'] %>"></script>
<% } %>
11 changes: 5 additions & 6 deletions packages/cli/lib/resources/head-end.ejs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<link rel="manifest" href="<%= htmlWebpackPlugin.files.publicPath %>manifest.json">
<% if (htmlWebpackPlugin.options.manifest.theme_color) { %>
<meta name="theme-color" content="<%= htmlWebpackPlugin.options.manifest.theme_color %>">
<% if (cli.manifest.theme_color) { %>
<meta name="theme-color" content="<%= cli.manifest.theme_color %>">
<% } %>
<% const loadManifest = htmlWebpackPlugin.options.createLoadManifest(compilation.assets, webpack.namedChunkGroups);%>
<% const filesRegexp = htmlWebpackPlugin.options.inlineCss ? /\.(chunk\.\w{5}\.css|js)$/ : /\.(css|js)$/;%>
<% for (const file in loadManifest[htmlWebpackPlugin.options.url]) { %>
<% if (htmlWebpackPlugin.options.preload && file && file.match(filesRegexp)) { %>
<% const filesRegexp = cli.inlineCss ? /\.(chunk\.\w{5}\.css|js)$/ : /\.(css|js)$/;%>
<% for (const file in cli.loadManifest[cli.url]) { %>
<% if (cli.preload && file && file.match(filesRegexp)) { %>
<% /* crossorigin for main bundle as that is loaded from `<script type=module` tag, other lazy loaded bundles are from webpack so its not needed */ %>
<link rel="preload" href="<%= htmlWebpackPlugin.files.publicPath + file %>" as="<%= file.match(/\.css$/)?'style':'script' %>" <%= file.match(/bundle\.\w{5}\.esm\.js$/)?'crossorigin="anonymous"':'' %>>
<% } %>
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
"compression-webpack-plugin": "^6.1.1",
"console-clear": "^1.0.0",
"copy-webpack-plugin": "^6.4.0",
"critters-webpack-plugin": "^2.5.0",
"critters-webpack-plugin": "^3.0.2",
"cross-spawn-promise": "^0.10.1",
"css-loader": "^5.2.7",
"dotenv": "^16.0.0",
Expand All @@ -106,8 +106,8 @@
"get-port": "^5.0.0",
"gittar": "^0.1.0",
"glob": "^8.0.3",
"html-webpack-exclude-assets-plugin": "0.0.7",
"html-webpack-plugin": "^3.2.0",
"html-webpack-plugin": "^4.5.2",
"html-webpack-skip-assets-plugin": "1.0.3",
"ip": "^1.1.8",
"isomorphic-unfetch": "^3.1.0",
"kleur": "^4.1.4",
Expand Down
11 changes: 5 additions & 6 deletions packages/cli/tests/images/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ exports.prerender.heads.home = `
<link rel="apple-touch-icon" href=\\"\\/assets\\/icons\\/apple-touch-icon\\.png\\">
<link rel="manifest" href="\\/manifest\\.json">
<style>html{padding:0}<\\/style>
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"only x\\" onload=\\"this.media='all'\\">
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"print\\" onload=\\"this.media='all'\\">
<noscript>
<link rel=\\"stylesheet\\" href=\\"\\/bundle.\\w{5}.css\\">
</noscript>
Expand All @@ -86,7 +86,7 @@ exports.prerender.heads.route66 = `
<link rel="apple-touch-icon" href=\\"\\/assets\\/icons\\/apple-touch-icon\\.png\\">
<link rel="manifest" href="\\/manifest\\.json">
<style>html{padding:0}<\\/style>
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"only x\\" onload=\\"this.media='all'\\">
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"print\\" onload=\\"this.media='all'\\">
<noscript>
<link rel=\\"stylesheet\\" href=\\"\\/bundle.\\w{5}.css\\">
</noscript>
Expand All @@ -103,7 +103,7 @@ exports.prerender.heads.custom = `
<link rel="apple-touch-icon" href=\\"\\/assets\\/icons\\/apple-touch-icon\\.png\\">
<link rel="manifest" href="\\/manifest\\.json">
<style>html{padding:0}<\\/style>
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"only x\\" onload=\\"this.media='all'\\">
<link href=\\"/bundle.\\w{5}.css\\" rel=\\"stylesheet\\" media=\\"print\\" onload=\\"this.media='all'\\">
<noscript>
<link rel=\\"stylesheet\\" href=\\"\\/bundle.\\w{5}.css\\">
</noscript>
Expand All @@ -125,7 +125,7 @@ exports.preload.true = `
<link rel=\\"preload\\" href=\\"\\/route-home\\.chunk\\.\\w{5}\\.js\\" as=\\"script\\">
<link rel=\\"preload\\" href=\\"\\/route-home\\.chunk\\.\\w{5}\\.css\\" as=\\"style\\">
<style>html{padding:0}<\\/style>
<link href=\\"\\/bundle\\.\\w{5}\\.css\\" rel=\\"stylesheet\\" media=\\"only x\\" onload=\\"this.media='all'\\">
<link href=\\"\\/bundle\\.\\w{5}\\.css\\" rel=\\"stylesheet\\" media=\\"print\\" onload=\\"this.media='all'\\">
<noscript>
<link rel=\\"stylesheet\\" href=\\"\\/bundle.\\w{5}.css\\">
</noscript>
Expand All @@ -142,7 +142,7 @@ exports.preload.false = `
<link rel=\\"apple-touch-icon\\" href=\\"\\/assets\\/icons\\/apple-touch-icon\\.png\\">
<link rel=\\"manifest\\" href=\\"\\/manifest\\.json\\">
<style>html{padding:0}<\\/style>
<link href=\\"\\/bundle\\.\\w{5}\\.css\\" rel=\\"stylesheet\\" media=\\"only x\\" onload=\\"this.media='all'\\">
<link href=\\"\\/bundle\\.\\w{5}\\.css\\" rel=\\"stylesheet\\" media=\\"print\\" onload=\\"this.media='all'\\">
<noscript>
<link rel=\\"stylesheet\\" href=\\"\\/bundle.\\w{5}.css\\">
</noscript>
Expand Down Expand Up @@ -320,7 +320,6 @@ exports.publicPath = `
<link rel="apple-touch-icon" href="/example-path/assets/icons/apple-touch-icon.png">
<link rel="manifest" href="/example-path/manifest.json">
<link href="/example-path/bundle.\\w{5}.css" rel="stylesheet">
<style></style>
</head>
<body>
<h1>Public path test</h1>
Expand Down
8 changes: 3 additions & 5 deletions packages/cli/tests/subjects/custom-template/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@
<head>
<meta charset="utf-8">
<title><% preact.title %></title>
<% if (htmlWebpackPlugin.options.config.isProd) { %>
<% if (cli.config.isProd) { %>
<meta name="example-meta" content="Hello World">
<% } %>
<% preact.headEnd %>
</head>
<body>
<h1>Guess what</h1>
<%= htmlWebpackPlugin.options.ssr({
url: '/'
}) %>
<script defer src="<%= htmlWebpackPlugin.files.chunks['bundle'].entry %>"></script>
<%= cli.ssr %>
<script defer src="<%= cli.entrypoints['bundle'] %>"></script>
<% preact.bodyEnd %>
</body>
</html>
4 changes: 2 additions & 2 deletions packages/prerender-data-provider/src/hook.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ function usePrerenderData(props, doAutomaticFetch = true) {
}
}

if (contextValue.CLI_DATA && contextValue.CLI_DATA.preRenderData) {
value = contextValue.CLI_DATA.preRenderData;
if (contextValue) {
value = contextValue;
}

const data = getPrerenderdata(state.value || value, props);
Expand Down
4 changes: 2 additions & 2 deletions packages/prerender-data-provider/src/render-prop.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ class PreRenderDataSource extends Component {
{contextValue => {
let obtainedContextValue;
// If the data is in script tag, it will be accesible from the following chaining
if (contextValue.CLI_DATA && contextValue.CLI_DATA.preRenderData) {
obtainedContextValue = contextValue.CLI_DATA.preRenderData;
if (contextValue) {
obtainedContextValue = contextValue;
}
const preRenderDataToBePassed = getPrerenderdata(
value || obtainedContextValue,
Expand Down
Loading

0 comments on commit 90d4596

Please sign in to comment.