New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

html-bundler-webpack-plugin

Package Overview
Dependencies
Maintainers
1
Versions
192
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

html-bundler-webpack-plugin - npm Package Compare versions

Comparing version 2.5.1 to 2.6.0

9

CHANGELOG.md
# Change log
## 2.6.0 (2023-08-09)
- feat: add the `css.chunkFilename` option for output filename of non-initial chunk files
- feat: add the `hotUpdate` option to enable/disable live reload in serve/watch mode
- fix: missing an output css file when the same style file is imported in js and linked in html
- chore: add the "hello world" example
- chore: add simple-site example with automatically processing many HTML templates
- chore: add the Handlebars example
- chore: add react-app example, ejected from `create-react-app` (alpha version)
## 2.5.1 (2023-08-04)

@@ -4,0 +13,0 @@ - fix: missing output html file after renaming template file in watch mode when using entry as a path

18

package.json
{
"name": "html-bundler-webpack-plugin",
"version": "2.5.1",
"description": "HTML bundler plugin for webpack handels a template as an entry point, extracts CSS and JS from their sources referenced in HTML, supports template engines like Eta, EJS, Handlebars, Nunjucks.",
"version": "2.6.0",
"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",
"webpack",

@@ -10,5 +11,2 @@ "plugin",

"bundler",
"extract",
"inline",
"html",
"template",

@@ -23,6 +21,10 @@ "ejs",

"scss",
"sass",
"css",
"js",
"inline",
"style",
"extract",
"script",
"js",
"javascript",
"svg"

@@ -105,4 +107,4 @@ ],

"devDependencies": {
"@babel/core": "^7.22.9",
"@babel/preset-env": "^7.22.9",
"@babel/core": "^7.22.10",
"@babel/preset-env": "^7.22.10",
"@test-fixtures/js": "0.0.2",

@@ -109,0 +111,0 @@ "@test-fixtures/lorem": "0.0.2",

@@ -11,4 +11,2 @@ /**

/**
* TODO: test experiments.css
*
* @this {import("webpack").LoaderContext<LoaderOptions>}

@@ -18,2 +16,3 @@ * @param {string} content

const loader = function (content) {
/* istanbul ignore next */
if (this._compiler.options?.experiments?.css && this._module?.type === 'css') {

@@ -48,3 +47,3 @@ return content;

return '/* extracted by HTMLBundler CSSLoader */ export {};';
return '/* extracted by HTMLBundler CSSLoader */';
};

@@ -51,0 +50,0 @@

const Resolver = require('../Resolver');
const Collection = require('../../Plugin/Collection');
const PluginService = require('../../Plugin/PluginService');
const { hmrFile, injectBeforeEndHead } = require('../Utils');

@@ -41,10 +42,2 @@ const { errorToHtml } = require('../Messages/Exeptions');

*/
encodeFile(file) {
return `\\u0027 + \\u0027${file}\\u0027 + \\u0027`;
}
/**
* @param {string} file
* @return {string}
*/
encodeRequire(file) {

@@ -126,4 +119,4 @@ return `\\u0027 + require(\\u0027${file}\\u0027) + \\u0027`;

export(content, data, issuer) {
if (this.hot) {
// note: it can be tested only manually, because Webpack API no provide `loaderContext.hot` for testing
/* istanbul ignore next: Webpack API no provide `loaderContext.hot` for testing */
if (this.hot && PluginService.useHotUpdate()) {
content = this.injectHmrFile(content);

@@ -145,5 +138,8 @@ Collection.add({ type: 'script', resource: hmrFile, issuer });

let content = errorToHtml(error);
content = this.injectHmrFile(content);
Collection.add({ type: 'script', resource: hmrFile, issuer });
if (PluginService.useHotUpdate()) {
content = this.injectHmrFile(content);
Collection.add({ type: 'script', resource: hmrFile, issuer });
}
return this.exportCode + "'" + this.decodeReservedChars(content) + "';";

@@ -150,0 +146,0 @@ }

@@ -125,2 +125,3 @@ const path = require('path');

this.beforeResolve = this.beforeResolve.bind(this);
this.afterResolve = this.afterResolve.bind(this);
this.afterCreateModule = this.afterCreateModule.bind(this);

@@ -231,9 +232,7 @@ this.beforeLoader = this.beforeLoader.bind(this);

UrlDependency.init({
fs,
moduleGraph: compilation.moduleGraph,
});
UrlDependency.init(fs, compilation);
// resolve modules
normalModuleFactory.hooks.beforeResolve.tap(pluginName, this.beforeResolve);
normalModuleFactory.hooks.afterResolve.tap(pluginName, this.afterResolve);
contextModuleFactory.hooks.alternativeRequests.tap(pluginName, this.filterAlternativeRequests);

@@ -294,2 +293,3 @@

/* istanbul ignore next: this method is called in watch mode after changes */
/**

@@ -432,5 +432,3 @@ * Invalidate changed file.

beforeResolve(resolveData) {
const { context, request, contextInfo, dependencyType } = resolveData;
// note: the contextInfo.issuer is the filename w/o a query
const { issuer } = contextInfo;
const { request, dependencyType } = resolveData;
const [file] = request.split('?', 1);

@@ -440,2 +438,3 @@

/* istanbul ignore next */
// prevent compilation of renamed or deleted entry point in serve/watch mode

@@ -453,13 +452,23 @@ if (Options.isDynamicEntry() && AssetEntry.isDeletedEntryFile(file)) {

// skip data-URL
if (request.startsWith('data:')) return;
// skip the module loaded via importModule
if (dependencyType === 'loaderImport') return;
if (dependencyType === 'url') {
UrlDependency.resolve(resolveData);
return;
}
}
/**
* Called after the request is resolved.
*
* @param {Object} resolveData
* @return {boolean|undefined} Return undefined to processing, false to ignore dependency.
*/
afterResolve(resolveData) {
const { request, contextInfo, dependencyType, createData } = resolveData;
const { resource, loaders } = createData;
const [file] = resource.split('?', 1);
// note: the contextInfo.issuer is the filename w/o a query
const { issuer } = contextInfo;
// skip: module loaded via importModule, css url, data-URL
if (dependencyType === 'loaderImport' || dependencyType === 'url' || request.startsWith('data:')) return;
if (issuer) {

@@ -480,9 +489,25 @@ const isIssuerStyle = Options.isStyle(issuer);

if (isIssuerStyle && file.endsWith('.js')) {
const rootIssuer = Collection.findRootIssuer(issuer);
resolveData._isScript = true;
const rootIssuer = Collection.findRootIssuer(issuer);
// return true if the root issuer is a JS (not style and not template), otherwise return false
return rootIssuer != null && !Options.isStyle(rootIssuer) && !Options.isEntry(rootIssuer);
}
// try to detect imported style as resolved resource file, because a request can be a node module w/o an extension
// the issuer can be a style if a scss contains like `@import 'main.css'`
if (!Options.isStyle(issuer) && !Options.isEntry(issuer) && Options.isStyle(file)) {
const rootIssuer = Collection.findRootIssuer(issuer);
Collection.importStyleRootIssuers.add(rootIssuer || issuer);
resolveData._isImportedStyle = true;
if (!createData.request.includes(cssLoader.loader)) {
// the request of an imported style must be different from the request for the same style specified in a html,
// otherwise webpack doesn't apply the added loader for the imported style,
// see the test case js-import-css-same-in-many4
createData.request = `${cssLoader.loader}!${createData.request}`;
loaders.unshift(cssLoader);
}
}
}

@@ -509,2 +534,3 @@

module._isStyle = Options.isStyle(resource);
module._isImportedStyle = resolveData._isImportedStyle === true;
module._isLoaderImport = dependencyType === 'loaderImport';

@@ -518,28 +544,5 @@ module._isDependencyUrl = dependencyType === 'url';

const { issuer } = resolveData.contextInfo;
const [file] = resource.split('?', 1);
if (!issuer || AssetInline.isDataUrl(rawRequest)) return;
// try to detect imported style as resolved resource file, because a request can be a node module w/o an extension
// the issuer can be a style if a scss contains like `@import 'main.css'`
if (issuer && !Options.isStyle(issuer) && !Options.isEntry(issuer) && Options.isStyle(file)) {
const rootIssuer = Collection.findRootIssuer(issuer);
module._isImportedStyle = true;
Collection.importStyleRootIssuers.add(rootIssuer || issuer);
// check entryId to avoid adding duplicate loaders after changes in serve mode
// add the CSS loader for only styles imported in JavaScript
if (!request.includes(cssLoader)) {
module.loaders.unshift(cssLoader);
// set the correct module type to enable the usage of built-in CSS support together with the bundler plugin
// if (this.compilation.compiler.options?.experiments?.css && type === 'css') {
// module.type = 'javascript/auto';
// }
}
return;
}
if (type === 'asset/inline' || type === 'asset' || (type === 'asset/source' && AssetInline.isSvgFile(resource))) {

@@ -876,2 +879,3 @@ AssetInline.add(resource, issuer, Options.isEntry(issuer));

resource: issuer,
useChunkFilename: true,
});

@@ -951,7 +955,9 @@ const assetFile = inline ? this.getInlineStyleAsseFile(filename, entryFilename) : filename;

* @param {string} resource
* @param {boolean} useChunkFilename
* @return {{isCached: boolean, filename: string}}
*/
getStyleAsseFile({ name, chunkId, hash, resource }) {
getStyleAsseFile({ name, chunkId, hash, resource, useChunkFilename = false }) {
const { compilation } = this;
const cssOptions = Options.getCss();
const filenameTemplate = useChunkFilename ? cssOptions.chunkFilename : cssOptions.filename;

@@ -969,3 +975,3 @@ /** @type {PathData} The data to generate an asset path by the filename template. */

const assetPath = compilation.getAssetPath(cssOptions.filename, pathData);
const assetPath = compilation.getAssetPath(filenameTemplate, pathData);
const outputFilename = Options.resolveOutputFilename(assetPath, cssOptions.outputPath);

@@ -972,0 +978,0 @@ const [sourceFile] = resource.split('?', 1);

@@ -424,2 +424,3 @@ const fs = require('fs');

/* istanbul ignore next: this method is called in watch mode after changes */
/**

@@ -477,2 +478,3 @@ * Add the entry file to compilation.

/* istanbul ignore next: this method is called in watch mode after changes */
/**

@@ -479,0 +481,0 @@ * Remove the entry file from cache.

@@ -229,6 +229,6 @@ const path = require('path');

const walk = (module) => {
const deps = module.dependencies;
const { dependencies } = module;
const result = [];
for (const dependency of deps) {
for (const dependency of dependencies) {
if (!dependency.userRequest) continue;

@@ -239,2 +239,8 @@

if (!depModule) {
// prevent a potential error in as yet unknown use cases to find the location of the bug
/* istanbul ignore next */
continue;
}
// use the original NormalModule instead of ConcatenatedModule

@@ -241,0 +247,0 @@ if (!depModule.resource && depModule.rootModule) {

@@ -16,9 +16,9 @@ const path = require('path');

* Must be an absolute or a relative by the context path.
* @property {CssOptions=} css The options for embedded plugin module to extract CSS.
* @property {JsOptions=} js The options for embedded plugin module to extract CSS.
* @property {function(string, ResourceInfo, Compilation): string|null =} postprocess The post-process for extracted content from entry.
* @property {CssOptions?} css The options for embedded plugin module to extract CSS.
* @property {JsOptions?} js The options for embedded plugin module to extract CSS.
* @property {function(string, ResourceInfo, Compilation): string|null ?} postprocess The post-process for extracted content from entry.
* @property {function(content: string, {sourceFile: string, assetFile: string})} afterProcess Called after processing all plugins.
* @property {boolean} [extractComments = false] Whether comments should be extracted to a separate file.
* If the original filename is foo.js, then the comments will be stored to foo.js.LICENSE.txt.
* This option enable/disable storing of *.LICENSE.txt file.
* This option enables/disable storing of *.LICENSE.txt file.
* For more flexibility use terser-webpack-plugin https://webpack.js.org/plugins/terser-webpack-plugin/#extractcomments.

@@ -29,4 +29,5 @@ * @property {Object|string} entry The entry points.

* @property {{paths: Array<string>, files: Array<RegExp>, ignore: Array<RegExp>}} watchFiles Paths and files to watch file changes.
* @property {Object=} loaderOptions Options defined in plugin but provided for the loader.
* @property {Array<Object>|boolean=} preload Options to generate preload link tags for assets.
* @property {boolean?} [hotUpdate=true] Whether in serve/watch mode should be added hot-update.js file in html.
* @property {Object?} loaderOptions Options defined in plugin but provided for the loader.
* @property {Array<Object>|boolean?} preload Options to generate preload link tags for assets.
* @property {boolean|Object|'auto'|null} [minify = false] Minify generated HTML.

@@ -41,3 +42,3 @@ * @property {boolean|Object|'auto'|null} [minifyOptions = null] Minification options, it is used for auto minify.

* @property {string|function(PathData, AssetInfo): string} [chunkFilename = '[id].js'] The output filename of non-initial chunk files.
* @property {boolean|string} [`inline` = false] Whether the compiled JS should be inlined.
* @property {boolean|string} [inline = false] Whether the compiled JS should be inlined.
*/

@@ -49,4 +50,5 @@

* @property {string|null} [outputPath = options.output.path] The output directory for an asset.
* @property {string|function(PathData, AssetInfo): string} [filename = '[name].js'] The file name of output file.
* @property {boolean|string} [`inline` = false] Whether the compiled CSS should be inlined.
* @property {string|function(PathData, AssetInfo): string} [filename = '[name].css'] The file name of output file.
* @property {string|function(PathData, AssetInfo): string} [chunkFilename = filename] The output filename of non-initial chunk files, e.g., styles imported in js.
* @property {boolean|string} [inline = false] Whether the compiled CSS should be inlined.
*/

@@ -67,3 +69,3 @@

chunkFilename: undefined, // used output.chunkFilename
outputPath: null,
outputPath: undefined,
inline: false,

@@ -75,3 +77,4 @@ };

filename: '[name].css',
outputPath: null,
chunkFilename: undefined,
outputPath: undefined,
inline: false,

@@ -97,2 +100,3 @@ };

if (!options.watchFiles) this.options.watchFiles = {};
this.options.hotUpdate = this.options.hotUpdate !== false;
}

@@ -130,2 +134,6 @@

if (!css.chunkFilename) {
css.chunkFilename = css.filename;
}
js.enabled = this.toBool(js.enabled, true, this.js.enabled);

@@ -132,0 +140,0 @@ js.inline = this.toBool(js.inline, false, this.js.inline);

@@ -20,3 +20,4 @@ /**

static #used = false;
static #watchMode = false;
static #watchMode;
static #hotUpdate;
static #contextCache = new Set();

@@ -61,2 +62,3 @@ static dataFiles = new Map();

this.#watchMode = false;
this.#hotUpdate = pluginOptions.hotUpdate;
this.#options = options;

@@ -134,2 +136,5 @@ this.#loaderOptions = loaderOptions;

/**
* @return {boolean}
*/
static isWatchMode() {

@@ -139,2 +144,9 @@ return this.#watchMode;

/**
* @return {boolean}
*/
static useHotUpdate() {
return this.#hotUpdate;
}
static isCached(context) {

@@ -141,0 +153,0 @@ if (this.#contextCache.has(context)) return true;

@@ -99,3 +99,3 @@ const path = require('path');

/**
* Resolve the full path of asset source file by raw request and issuer.
* Resolve the full path of asset source file.
*

@@ -106,13 +106,14 @@ * @param {string} rawRequest The raw request of resource.

*/
static getSourceFile(rawRequest, issuer) {
let sourceFile = this.sourceFiles.get(issuer)?.get(rawRequest);
if (sourceFile) return sourceFile;
static resolveResource(rawRequest, issuer) {
let resource = this.sourceFiles.get(issuer)?.get(rawRequest);
if (resource) return resource;
// normalize request, e.g. the relative `path/to/../to/file` path to absolute `path/to/file`
sourceFile = path.resolve(this.context, rawRequest);
const [file] = sourceFile.split('?', 1);
// normalize request, e.g., the relative `path/to/../to/file` path to absolute `path/to/file`
resource = path.resolve(this.context, rawRequest);
const [file] = resource.split('?', 1);
if (rawRequest.startsWith(this.context) || this.fs.existsSync(file)) {
this.addSourceFile(sourceFile, rawRequest, issuer);
return sourceFile;
this.addSourceFile(resource, rawRequest, issuer);
return resource;
}

@@ -230,3 +231,3 @@

const resource = this.getSourceFile(rawRequest, issuerFile);
const resource = this.resolveResource(rawRequest, issuerFile);

@@ -233,0 +234,0 @@ // resolve resource

@@ -5,4 +5,4 @@ const path = require('path');

class UrlDependency {
static fs = null;
static compilation = null;
static fs;
static moduleGraph;

@@ -13,5 +13,5 @@ /**

*/
static init({ fs, moduleGraph }) {
static init(fs, compilation) {
this.fs = fs;
this.moduleGraph = moduleGraph;
this.moduleGraph = compilation.moduleGraph;
}

@@ -26,5 +26,7 @@

const fs = this.fs;
const [file, query] = resolveData.request.split('?');
const rawRequest = resolveData.request;
const [file, query] = rawRequest.split('?');
const resource = path.resolve(resolveData.context, file);
if (!fs.existsSync(path.resolve(resolveData.context, file))) {
if (!fs.existsSync(resource)) {
const dependency = resolveData.dependencies[0];

@@ -35,11 +37,6 @@ const parentModule = this.moduleGraph.getParentModule(dependency);

if (sourceFile != null) {
const resolvedRequest = query ? sourceFile + '?' + query : sourceFile;
const rawRequest = resolveData.request;
const issuer = resolveData.contextInfo.issuer;
resolveData.request = resolvedRequest;
dependency.request = resolvedRequest;
dependency.userRequest = resolvedRequest;
Resolver.addSourceFile(resolvedRequest, rawRequest, issuer);
resolveData.request = query ? sourceFile + '?' + query : sourceFile;
Resolver.addSourceFile(resolveData.request, rawRequest, issuer);
}

@@ -46,0 +43,0 @@ }

@@ -39,2 +39,3 @@ import { Compiler, Compilation, LoaderContext, WebpackPluginInstance } from 'webpack';

watchFiles?: WatchFiles;
hotUpdate?: boolean;
verbose?: 'auto' | boolean;

@@ -101,2 +102,3 @@ /**

filename?: FilenameTemplate;
chunkFilename?: FilenameTemplate;
outputPath?: string;

@@ -103,0 +105,0 @@ inline?: 'auto' | boolean;

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc