Skip to content

Commit

Permalink
fix: serialization issue when used the cache.type = filesystem, #73
Browse files Browse the repository at this point in the history
  • Loading branch information
webdiscus committed Jan 28, 2024
1 parent bc12d1f commit 23711bf
Show file tree
Hide file tree
Showing 26 changed files with 275 additions and 81 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change log

## 3.4.12 (2024-01-29)

- fix: serialization issue when used the `cache.type = 'filesystem'`
- fix: missing output js files after second run build when used the `cache.type = 'filesystem'`

## 3.4.11 (2024-01-22)

- fix: error by resolving url() in the CSS file defined in the entry option
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "html-bundler-webpack-plugin",
"version": "3.4.11",
"version": "3.4.12",
"description": "HTML bundler plugin for webpack handles a template as an entry point, extracts CSS and JS from their sources referenced in HTML, supports template engines like Eta, EJS, Handlebars, Nunjucks.",
"keywords": [
"html",
Expand Down
2 changes: 1 addition & 1 deletion src/Plugin/AssetCompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ class AssetCompiler {
AssetEntry.init({ compilation, entryLibrary: this.entryLibrary, collection: Collection });
AssetTrash.init(compilation);
CssExtractModule.init(compilation);
Collection.init(compilation, AssetCompiler.getHooks(compilation));
Collection.init({ compilation, assetEntry: AssetEntry, hooks: AssetCompiler.getHooks(compilation) });

Resolver.init({
fs,
Expand Down
17 changes: 10 additions & 7 deletions src/Plugin/AssetEntry.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ const loader = require.resolve('../Loader');
* [name], [base], [path], [ext], [id], [contenthash], [contenthash:nn]
* See https://webpack.js.org/configuration/output/#outputfilename
* @property {Function} filenameFn The function to generate the output filename dynamically.
* TODO: remove filename or assetFile, currently the assetFile is undeined (unused?)
* @property {string=} assetFile The output asset file with the relative path by webpack output path.
* Note: the method compilation.emitAsset() use this file as the key of an asset object
* and save the file relative by output path, defined in webpack.options.output.path.
* @property {string} resource The absolute import file with a query.
* @property {string} importFile The original import entry file.
* @property {string} sourceFile The absolute import file only w/o a query.
Expand Down Expand Up @@ -114,7 +110,7 @@ class AssetEntry {

for (let name in pluginEntry) {
const entry = pluginEntry[name];
const entryName = `${this.entryNamePrefix}${name}`;
const entryName = this.createEntryName(name);

if (entry.import == null) {
if (Option.isEntry(entry)) {
Expand Down Expand Up @@ -162,13 +158,21 @@ class AssetEntry {
files.forEach((file) => {
const outputFile = path.relative(dir, file);
const name = outputFile.slice(0, outputFile.lastIndexOf('.'));
const entryName = `${this.entryNamePrefix}${name}`;
const entryName = this.createEntryName(name);
entry[entryName] = { import: [file] };
});

return entry;
}

/**
* @param {string} name
* @return {string}
*/
static createEntryName(name) {
return `${this.entryNamePrefix}${name}`;
}

/**
* @param {string} name
* @return {string}
Expand Down Expand Up @@ -457,7 +461,6 @@ class AssetEntry {
originalName,
filenameTemplate,
filename: undefined,
assetFile: undefined,
resource,
importFile,
sourceFile,
Expand Down
104 changes: 33 additions & 71 deletions src/Plugin/Collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class Collection {
/** @type {Compilation} */
static compilation;

/** @type {AssetEntry} */
static assetEntry;

static assets = new Map();

/** @type {Map<string, {entry: AssetEntryOptions, assets: Array<{}>} >} Entries data */
Expand Down Expand Up @@ -330,10 +333,12 @@ class Collection {

/**
* @param {Compilation} compilation
* @param {AssetEntry} assetEntry
* @param {HtmlBundlerPlugin.Hooks} hooks
*/
static init(compilation, hooks) {
static init({ compilation, assetEntry, hooks }) {
this.compilation = compilation;
this.assetEntry = assetEntry;
this.hooks = hooks;
}

Expand Down Expand Up @@ -1005,41 +1010,6 @@ class Collection {
});
}

// TODO: add hook for addHeadTags: beforeStyles, beforeScripts, endHead
// let res = this.hooks.insertHeadTags.call(content);
// if (res && Array.isArray(res.tags)) {
// let headTags = res.tags;
// let pos = res.pos;
// let sep = Option.isMinify() ? '' : '\n';
// let headBlock = headTags.join(sep);
//
// let startPos;
// let headEndPos = content.indexOf('</head>');
// let headEndPosRegExp = /<\/head>/;
// let posRegexp;
//
// if (!isNumber(pos)) {
// switch (pos) {
// case 'beforePreload':
// posRegexp = /<link.+rel="preload"/;
// break;
// case 'beforeStyles':
// posRegexp = /<link.+rel=".*stylesheet.*"/;
// break;
// case 'beforeScripts':
// posRegexp = /<script/;
// break;
// case 'endHead':
// // through
// case 'default':
// startPos;
// break;
// }
//
// const match = posRegexp.exec(content);
// }
// }

// 9. beforeEmit hook allows plugins to change the html after chunks and inlined assets are injected
promise = promise.then((content) => hooks.beforeEmit.promise(content, compileEntry) || content);

Expand Down Expand Up @@ -1118,14 +1088,38 @@ class Collection {
this.importStyleSources.clear();
}

/**
* Called by first start or after changes.
*
* @param {Function} write The serialize function.
*/
static serialize({ write }) {
for (let [, { entry }] of this.data) {
// note: set the function properties as null to able the serialization of the entry object,
// the original functions will be recovered by deserialization from the cached object `AssetEntry`
entry.filenameFn = null;
entry.filenameTemplate = null;
}

write(this.assets);
write(this.data);
}

/**
* @param {Function} read The deserialize function.
*/
static deserialize({ read }) {
this.assets = read();
this.data = read();

for (let [, { entry }] of this.data) {
const cachedEntry = this.assetEntry.entriesById.get(entry.id);

// recovery original not serializable functions from the object cached in the memory
entry.filenameFn = cachedEntry.filenameFn;
entry.filenameTemplate = cachedEntry.filenameTemplate;
}

this.isDeserialized = true;
}

Expand All @@ -1140,45 +1134,13 @@ class Collection {
*/
static addToCompilationDeserializedFiles(issuer) {
for (const [resource, item] of this.assets) {
const { isCompiled, type, name, entries } = item;
if (!isCompiled && type === this.type.script && entries.has(issuer)) {
item.isCompiled = true;
const { type, name, entries } = item;

if (type === this.type.script && entries.has(issuer)) {
this.#addToCompilation({ name, resource, issuer });
}
}
}

/**
* TODO: Reserved for debug.
*/
// static getResourceIssuers(resource) {
// const item = this.assets.get(resource);
//
// if (!item) return [];
//
// const issuers = Array.from(item.entries.keys());
//
// // extract from all issuer's request only filename, w/o a query
// issuers.forEach((request, index) => {
// let [file] = request.split('?', 1);
// issuers[index] = file;
// });
//
// return issuers;
// }

/**
* TODO: Reserved for debug.
*/
// static getCompilationModule(resource) {
// const { modules } = this.compilation;
// for (const module of modules) {
// if (module.resource === resource) {
// return module;
// }
// }
// return null;
// }
}

module.exports = Collection;
10 changes: 10 additions & 0 deletions test/cases/cache-filesystem-js/expected/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
<script src="main.6ad9992e.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions test/cases/cache-filesystem-js/expected/main.6ad9992e.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("Hello World! Test: 123");
10 changes: 10 additions & 0 deletions test/cases/cache-filesystem-js/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
<script src="main.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions test/cases/cache-filesystem-js/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello World! Test: 123');
45 changes: 45 additions & 0 deletions test/cases/cache-filesystem-js/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const path = require('path');
const HtmlBundlerPlugin = require('html-bundler-webpack-plugin');

module.exports = {
mode: 'production',
//mode: 'development',
stats: 'errors-warnings',

output: {
path: path.join(__dirname, 'dist/'),
clean: true,
},

plugins: [
new HtmlBundlerPlugin({
entry: {
index: {
import: './src/index.html',
filename: (pathData) => {
//console.log('\n\n*** entry.index.filename: : ', { pathData });
return '[name].html';
},
},
},

// filename: (pathData) => {
// console.log('\n\n*** plugin.filename: : ', { pathData });
// return '[name].html';
// },

js: {
filename: (pathData) => {
//console.log('\n\n*** js.filename: : ', { pathData });
return '[name].[contenthash:8].js';
},
},
}),
],

// test filesystem cache
cache: {
type: 'filesystem',
cacheDirectory: path.join(__dirname, '.cache'),
},
};
12 changes: 11 additions & 1 deletion test/integration.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { compareFiles, watchCompareFiles } from './utils/helpers';
import { compareFiles, compareFilesRuns, watchCompareFiles } from './utils/helpers';
//import { removeDirsSync } from './utils/file';

// Remove all 'dist/' directories from tests, use it only for some local tests.
Expand All @@ -22,6 +22,16 @@ describe('features tests', () => {
test('resolve-js-in-many-pages', () => compareFiles('resolve-js-in-many-pages'));
});

// TODO: test after N runs
// describe('cache tests', () => {
// afterEach(async () => {
// // sleep between tests to give time for GC
// await new Promise((r) => setTimeout(r, 500));
// });
//
// test('cache-filesystem-js3', () => compareFilesRuns('cache-filesystem-js', false, 3));
// });

describe('resolve files', () => {
test('script style asset', () => compareFiles('resolve-script-style-asset'));
test('many pages from same tmpl', () => compareFiles('resolve-in-many-pages-from-same-tmpl'));
Expand Down
4 changes: 4 additions & 0 deletions test/manual/cache-filesystem-js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Test

Test the `cache.type` as `filesystem` for simple JS app.
See the [issue 73](https://github.com/webdiscus/html-bundler-webpack-plugin/issues/73).
13 changes: 13 additions & 0 deletions test/manual/cache-filesystem-js/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"description": "IMPORTANT: don't install webpack here because the Webpack instance MUST be one, otherwise appear the error: The 'compilation' argument must be an instance of Compilation.",
"scripts": {
"start": "webpack serve --mode development",
"start:prod": "webpack serve --mode production",
"watch": "webpack watch --mode development",
"build": "webpack --mode=production --progress"
},
"license": "ISC",
"devDependencies": {
"html-bundler-webpack-plugin": "file:../../.."
}
}
10 changes: 10 additions & 0 deletions test/manual/cache-filesystem-js/src/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Test</title>
</head>
<body>
<h1>Hello World!</h1>
<script src="main.js"></script>
</body>
</html>
1 change: 1 addition & 0 deletions test/manual/cache-filesystem-js/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('Hello World! Test: 123');
Loading

0 comments on commit 23711bf

Please sign in to comment.