Skip to content

Commit 606eeab

Browse files
committed
fix: infinity walk by circular dependency, #59
1 parent 3394c31 commit 606eeab

323 files changed

Lines changed: 3064 additions & 1860 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change log
22

3+
## 3.4.4 (2023-12-28)
4+
5+
- fix: extract css from complex libs like MUI leads to an infinity walk by circular dependency, #59
6+
- test: refactor tests
7+
38
## 3.4.3 (2023-12-18)
49

510
- fix: favicon plugin causes a crash without an error explaining if no link tag is included

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,7 @@ See [boilerplate](https://github.com/webdiscus/webpack-html-scss-boilerplate)
393393
- Automatically processing **multiple HTML** templates [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-diop8g?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/simple-site/)
394394
- **Bootstrap** with Webpack [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-kjnlvk?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/bootstrap)
395395
- **Tailwind CSS** with Webpack [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-auem8r?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/tailwindcss/)
396+
- **Twig** with Webpack [View in browser](https://stackblitz.com/edit/twig-webpack?file=webpack.config.js)
396397
- **Handlebars** with Webpack [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-mxbx4t?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/handlebars/)
397398
- Extend **Handlebars layout** with blocks [View in browser](https://stackblitz.com/edit/webpack-webpack-js-org-bjtjvc?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/handlebars-layout/)
398399
- Auto generate **integrity hash** for `link` and `script` tags [View in browser](https://stackblitz.com/edit/webpack-integrity-hvnfmg?file=webpack.config.js) | [source](https://github.com/webdiscus/html-bundler-webpack-plugin/tree/master/examples/integrity/)
@@ -3516,6 +3517,13 @@ You can use a relative path:
35163517
> {% extends myTemplate %}
35173518
> ```
35183519

3520+
> **Warning**
3521+
>
3522+
> The Twig template containing `tabs` will not be compiled into HTML.\
3523+
> Use the `spaces` as an indent in templates.
3524+
> The `tabs` are not supported by `TwigJS`.
3525+
3526+
35193527
---
35203528

35213529
#### [↑ back to contents](#contents)

package-lock.json

Lines changed: 2496 additions & 1472 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "html-bundler-webpack-plugin",
3-
"version": "3.4.3",
3+
"version": "3.4.4",
44
"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.",
55
"keywords": [
66
"html",
@@ -120,42 +120,42 @@
120120
"html-minifier-terser": "^7.2.0"
121121
},
122122
"devDependencies": {
123-
"@babel/core": "^7.23.2",
124-
"@babel/preset-env": "^7.23.2",
125-
"@emotion/react": "^11.11.1",
123+
"@babel/core": "^7.23.6",
124+
"@babel/preset-env": "^7.23.6",
125+
"@emotion/react": "^11.11.3",
126126
"@emotion/styled": "^11.11.0",
127-
"@mui/material": "^5.14.19",
127+
"@mui/material": "^5.15.2",
128128
"@test/html-bundler-webpack-plugin": "file:./",
129129
"@test-fixtures/js": "0.0.2",
130130
"@test-fixtures/dius": "file:./test/fixtures/node_modules/dius/",
131131
"@test-fixtures/lorem": "file:./test/fixtures/node_modules/lorem/",
132132
"@test-fixtures/scss": "0.0.7",
133133
"@test/import-css": "file:./test/fixtures/node_modules/import-css/",
134-
"@types/jest": "^29.5.10",
134+
"@types/jest": "^29.5.11",
135135
"copy-webpack-plugin": "9.1.0",
136136
"css-loader": "^6.8.1",
137137
"css-minimizer-webpack-plugin": "^5.0.1",
138138
"ejs": "^3.1.9",
139-
"favicons": "^7.1.4",
139+
"favicons": "7.1.4",
140140
"handlebars": "^4.7.8",
141141
"handlebars-layouts": "^3.1.4",
142142
"jest": "^29.7.0",
143-
"liquidjs": "^10.9.4",
143+
"liquidjs": "^10.10.0",
144144
"mustache": "^4.2.0",
145145
"nunjucks": "^3.2.4",
146-
"prettier": "^3.1.0",
147-
"react": "^18.2.0",
148-
"react-dom": "^18.2.0",
146+
"prettier": "^3.1.1",
147+
"react": "18.2.0",
148+
"react-dom": "18.2.0",
149149
"responsive-loader": "^3.1.2",
150150
"rtlcss": "^4.1.1",
151151
"sass": "1.67.0",
152-
"sass-loader": "13.3.2",
152+
"sass-loader": "13.3.3",
153153
"sharp": "^0.32.6",
154154
"ts-loader": "9.5.1",
155-
"typescript": "5.3.2",
155+
"typescript": "5.3.3",
156156
"twig": "^1.17.1",
157-
"vue": "^3.3.9",
158-
"vue-loader": "^17.3.1",
157+
"vue": "3.3.13",
158+
"vue-loader": "^17.4.0",
159159
"webpack": "^5.89.0",
160160
"webpack-cli": "5.1.4",
161161
"webpack-dev-server": "^4.15.1"

src/Plugin/AssetCompiler.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -688,8 +688,6 @@ class AssetCompiler {
688688
}
689689

690690
AssetEntry.connectEntryAndModule(module, resolveData);
691-
// for debug only, don't use this id as real entryId, because the module.resourceResolveData is cached in serve mode
692-
meta._lastEntryId = resolveData.entryId;
693691

694692
// skip the module loaded via importModule
695693
if (meta.isLoaderImport || meta.isParentLoaderImport) return;
@@ -1014,7 +1012,12 @@ class AssetCompiler {
10141012
const modules = Collection.findImportedModules(entry.id, issuer, chunk);
10151013

10161014
// 2. squash styles from all nested files into one file
1017-
for (const module of modules) {
1015+
const uniqueModuleIds = new Set();
1016+
for (const { module } of modules) {
1017+
if (uniqueModuleIds.has(module.debugId)) {
1018+
continue;
1019+
}
1020+
10181021
const isUrl = module.resourceResolveData?.query.includes('url');
10191022
const importData = {
10201023
resource: module.resource,
@@ -1044,7 +1047,7 @@ class AssetCompiler {
10441047
}
10451048

10461049
if (isUrl) {
1047-
// get url of css output filename in js for lazy load
1050+
// get url of css output filename in js for the lazy load
10481051
Collection.setData(
10491052
entry,
10501053
{ resource: issuer },
@@ -1062,9 +1065,9 @@ class AssetCompiler {
10621065

10631066
cssHash += module.buildInfo.hash;
10641067
sources.push(...module._cssSource);
1065-
10661068
imports.push(importData);
10671069
resources.push(module.resource);
1070+
uniqueModuleIds.add(module.debugId);
10681071
}
10691072

10701073
if (sources.length === 0) continue;

src/Plugin/Collection.js

Lines changed: 14 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -451,7 +451,7 @@ class Collection {
451451
}
452452

453453
/**
454-
* Find styles from all nested JS files imported in the root JS file and sort them.
454+
* Find styles from all nested JS files.
455455
*
456456
* @param {number} entryId The entry id of the template where is the root issuer.
457457
* Note: the same issuer can be used in many entries.
@@ -462,38 +462,12 @@ class Collection {
462462
static findImportedModules(entryId, rootIssuer, chunk) {
463463
const issuerModule = this.getGraphModule(rootIssuer);
464464
const modules = this.findModuleDependencies(issuerModule);
465-
const uniqueModules = [];
466465

467466
// reserved for debug;
468467
// the modules are already sorted
469468
//modules.sort((a, b) => (a.order < b.order ? -1 : 1));
470469

471-
// TODO: research how to unique modules used in the current issuer and in deep nested issuers;
472-
// Currently the prio is for an first exemplar in nested issuers.
473-
// See the test js-import-css-order-dependencies.
474-
// For example:
475-
// 0: a.css
476-
// 1.0: common.css // currently, is kept this file (imported in the nested js component)
477-
// 3: b.css
478-
// 2: common.css // perhaps, should be kept this?
479-
for (const { module } of modules) {
480-
if (!uniqueModules.includes(module)) {
481-
uniqueModules.push(module);
482-
}
483-
}
484-
485-
// reserved for debug
486-
// console.log(
487-
// '\n### modules:\n',
488-
// modules.map(({ order, module }) => {
489-
// return {
490-
// order,
491-
// resource: path.basename(module.resource),
492-
// };
493-
// })
494-
// );
495-
496-
return uniqueModules;
470+
return modules;
497471
}
498472

499473
/**
@@ -502,13 +476,20 @@ class Collection {
502476
*/
503477
static findModuleDependencies(module) {
504478
const { moduleGraph } = this.compilation;
479+
const circularDependencyIds = new Set();
480+
const orderStack = [];
505481
let order = '';
506-
let orderStack = [];
507482

508483
const walk = (module) => {
509484
const { dependencies } = module;
510485
const result = [];
511486

487+
// avoid an infinity walk by circular dependency
488+
if (circularDependencyIds.has(module.debugId)) {
489+
return result;
490+
}
491+
circularDependencyIds.add(module.debugId);
492+
512493
for (const dependency of dependencies) {
513494
// TODO: detect whether the userRequest is a file, not a runtime, e.g. of vue
514495
if (
@@ -531,16 +512,17 @@ class Collection {
531512
depModule = depModule.rootModule;
532513
}
533514

534-
const parentIndex = moduleGraph.getParentBlockIndex(dependency);
515+
const index = moduleGraph.getParentBlockIndex(dependency);
535516

536517
if (depModule.dependencies.length > 0) {
537518
// save current order before recursive walking
538519
orderStack.push(order);
539-
order += (order ? '.' : '') + parentIndex;
520+
order += (order ? '.' : '') + index;
540521
result.push(...walk(depModule));
541522
} else if (depModule.resourceResolveData?._bundlerPluginMeta.isImportedStyle === true) {
542523
result.push({
543-
order: order + (order ? '.' : '') + parentIndex,
524+
resource: depModule.resource,
525+
order: order + (order ? '.' : '') + index,
544526
module: depModule,
545527
});
546528
}

test/cases/decode-chars/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const HtmlBundlerPlugin = require('../../../');
2+
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');
33

44
module.exports = {
55
mode: 'production',

test/cases/entry-css-single/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const HtmlBundlerPlugin = require('../../../');
2+
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');
33

44
module.exports = {
55
mode: 'production',

test/cases/entry-data-i18n-multipage-watch/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const HtmlBundlerPlugin = require('../../../');
2+
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');
33

44
const languages = {
55
'de-DE': require('./src/locales/de-DE.json'),

test/cases/entry-data-i18n-multipage/webpack.config.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const path = require('path');
2-
const HtmlBundlerPlugin = require('../../../');
2+
const HtmlBundlerPlugin = require('@test/html-bundler-webpack-plugin');
33

44
const languages = {
55
'de-DE': require('./src/locales/de-DE.json'),

0 commit comments

Comments
 (0)