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 1.3.1 to 1.4.0

src/Loader/Messages/Info.js

8

CHANGELOG.md
# Change log
## 1.4.0 (2023-02-26)
- feat: display watch files in watch/serv mode when verbose option is enabled
- feat: add `auto` value for the `verbose` option
- refactor: improve the code structure
- test: add tests for watch mode
- chore: add GitHub test badge
- docs: improve readme
## 1.3.1 (2023-02-24)

@@ -4,0 +12,0 @@ - fix: after an error, restore watching without restarting

25

package.json
{
"name": "html-bundler-webpack-plugin",
"version": "1.3.1",
"version": "1.4.0",
"description": "HTML bundler plugin for webpack handels HTML template as entry point, extracts CSS and JS from their sources specified in HTML.",

@@ -8,3 +8,16 @@ "keywords": [

"plugin",
"loader",
"bundler",
"bundle",
"extract",
"inline",
"html",
"template",
"ejs",
"handlebars",
"mustache",
"nunjucks",
"liquidjs",
"eta",
"hbs",
"scss",

@@ -15,11 +28,3 @@ "css",

"script",
"inline",
"svg",
"template",
"eta",
"ejs",
"handlebars",
"mustache",
"nunjucks",
"loader"
"svg"
],

@@ -26,0 +31,0 @@ "license": "ISC",

21

src/Common/Helpers.js

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

const isWin = path.sep === '\\';
const workingDir = process.env.PWD;

@@ -28,2 +27,20 @@ /**

/**
* Return the path of file relative to a directory.
*
* @param {string} file
* @param {string} dir
* @return {string}
*/
const pathRelativeByPwd = (file, dir = process.cwd()) => {
let relPath = file;
if (file.startsWith(dir)) {
relPath = path.relative(dir, file);
if (!path.extname(file)) relPath = path.join(relPath, path.sep);
}
return isWin ? pathToPosix(relPath) : relPath;
};
/**
* Parse the url query.

@@ -83,3 +100,3 @@ *

outToConsole,
workingDir,
pathRelativeByPwd,
};
const { minify } = require('html-minifier-terser');
const Options = require('./Plugin/Options');
const AssetCompiler = require('./Plugin/AssetCompiler');

@@ -7,20 +8,4 @@ const loader = require.resolve('./Loader');

/**
* @typedef {Object} PluginOptions
* @property {RegExp} [test = /\.(html)$/] The search for a match of entry files.
* @property {boolean} [enabled = true] Enable/disable the plugin.
* @property {boolean} [verbose = false] Show the information at processing entry files.
* @typedef {PluginOptions} HtmlBundlerPluginOptions
* @property {boolean|Object|'auto'|null} [minify = false] Minify generated HTML.
* @property {string|null} [sourcePath = options.context] The absolute path to sources.
* @property {string|null} [outputPath = options.output.path] The output directory for an asset.
* @property {string|function(PathData, AssetInfo): string} [filename = '[name].html'] The file name of output file.
* See https://webpack.js.org/configuration/output/#outputfilename.
* Must be an absolute or a relative by the context path.
* @property {function(string, ResourceInfo, Compilation): string|null} postprocess The post process for extracted content from entry.
* @property {Array<ModuleOptions>} [modules = []]
* @property {ModuleOptions|{}} css The options for embedded plugin module to extract CSS.
* @property {ExtractJsOptions|{}} js The options for embedded plugin module to extract CSS.
* @property {boolean} [`extractComments` = false] Whether comments shall 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.
* For more flexibility use terser-webpack-plugin https://webpack.js.org/plugins/terser-webpack-plugin/#extractcomments.
*/

@@ -30,7 +15,7 @@

/**
* @param {PluginOptions|{}} options
* @param {HtmlBundlerPluginOptions|{}} options
*/
constructor(options = {}) {
const PluginOptions = {
test: /\.(html|ejs)$/,
test: /\.(html|ejs|eta)$/,
enabled: true,

@@ -67,3 +52,3 @@ verbose: false,

const defaultLoader = {
test: /\.(html|ejs|eta)$/,
test: Options.get().test,
loader,

@@ -92,8 +77,8 @@ };

afterRenderModules(compilation) {
const options = this.options;
const { compiler, assets } = compilation;
const { mode } = compiler.options;
const { RawSource } = compiler.webpack.sources;
const isProductionMode = mode == null || mode === 'production';
const promises = [];
const options = Options.get();
let isMinify = Options.isTrue(options.minify, false);
let minifyOptions;

@@ -114,6 +99,6 @@

if (options.minify === true || (isProductionMode && options.minify === 'auto')) {
if (isMinify) {
minifyOptions = defaultMinifyOptions;
} else if (typeof options.minify === 'object' && options.minify !== null) {
minifyOptions = { ...defaultMinifyOptions, ...this.options.minify };
} else if (options.minify !== null && typeof options.minify === 'object') {
minifyOptions = { ...defaultMinifyOptions, ...options.minify };
} else {

@@ -120,0 +105,0 @@ return;

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

const { isWin } = require('./Utils');
const { verboseWatchFiles } = require('./Messages/Info');
const { watchPathsException } = require('./Messages/Exeptions');
const { outToConsole } = require('../Common/Helpers');

@@ -66,2 +68,6 @@ /**

files.forEach(loaderContext.addDependency);
if (PluginService.getOptions().isVerbose()) {
verboseWatchFiles([...this.files]);
}
}

@@ -68,0 +74,0 @@

const Eta = require('eta');
const PluginService = require('../Plugin/PluginService');
const { outToConsole } = require('../Common/Helpers');

@@ -41,3 +42,2 @@ /**

const watchFilesOption = PluginService.getOptions().watchFiles;
const watchFiles = {

@@ -55,3 +55,3 @@ // watch files only in the directories, defaults is the project directory

/[\\/]\..+$/, // hidden dirs and files: .git, .idea, .gitignore, etc.
/package(?:-lock)*.json$/,
/package(?:-lock)*\.json$/,
/webpack\.(.+)\.js$/,

@@ -62,33 +62,31 @@ /\.(je?pg|png|ico|webp|svg|woff2?|ttf|otf|eot)$/,

if (watchFilesOption) {
const { paths, files, ignore } = watchFilesOption;
const { paths, files, ignore } = PluginService.getOptions().getWatchFiles();
if (paths) {
const entries = Array.isArray(paths) ? paths : [paths];
for (let item of entries) {
watchFiles.paths.push(item);
}
if (paths) {
const entries = Array.isArray(paths) ? paths : [paths];
for (let item of entries) {
watchFiles.paths.push(item);
}
if (watchFiles.paths.length === 0) {
watchFiles.paths.push(this.rootContext);
}
}
if (watchFiles.paths.length < 1) {
watchFiles.paths.push(this.rootContext);
}
if (files) {
const entries = Array.isArray(files) ? files : [files];
for (let item of entries) {
if (item.constructor.name !== 'RegExp') {
item = new RegExp(item);
}
watchFiles.files.push(item);
if (files) {
const entries = Array.isArray(files) ? files : [files];
for (let item of entries) {
if (item.constructor.name !== 'RegExp') {
item = new RegExp(item);
}
watchFiles.files.push(item);
}
}
if (ignore) {
const entries = Array.isArray(ignore) ? ignore : [ignore];
for (let item of entries) {
if (item.constructor.name !== 'RegExp') {
item = new RegExp(item);
}
watchFiles.ignore.push(item);
if (ignore) {
const entries = Array.isArray(ignore) ? ignore : [ignore];
for (let item of entries) {
if (item.constructor.name !== 'RegExp') {
item = new RegExp(item);
}
watchFiles.ignore.push(item);
}

@@ -95,0 +93,0 @@ }

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

extensions: ['.scss', '.sass', '.css'],
restrictions: PluginService.getStyleRestrictions(),
restrictions: this.getStyleResolveRestrictions(),
});

@@ -59,2 +59,13 @@ }

/**
* Return a list of resolve restrictions to restrict the paths that a request can be resolved on.
* @see https://webpack.js.org/configuration/resolve/#resolverestrictions
* @return {Array<RegExp|string>}
*/
static getStyleResolveRestrictions() {
const restrictions = PluginService.getOptions().getCss().test;
return Array.isArray(restrictions) ? restrictions : [restrictions];
}
/**
* Resolve filename.

@@ -61,0 +72,0 @@ *

@@ -11,5 +11,5 @@ const vm = require('vm');

const Options = require('./Options');
const PluginService = require('./PluginService');
const ScriptCollection = require('./ScriptCollection');
const extractCss = require('./Modules/extractCss');

@@ -35,7 +35,3 @@ const Resolver = require('./Resolver');

const {
optionModulesException,
executeTemplateFunctionException,
postprocessException,
} = require('./Messages/Exception');
const { executeTemplateFunctionException, postprocessException } = require('./Messages/Exception');

@@ -57,3 +53,3 @@ /** @typedef {import('webpack').Compiler} Compiler */

* @property {boolean} [enabled = true] Enable/disable the plugin.
* @property {boolean} [verbose = false] Show the information at processing entry files.
* @property {boolean|string} [verbose = false] Show the information at processing entry files.
* @property {string} [sourcePath = options.context] The absolute path to sources.

@@ -67,8 +63,2 @@ * @property {string} [outputPath = options.output.path] The output directory for an asset.

/**
* @typedef {Object} ExtractJsOptions
* @property {boolean} [verbose = false] Show the information at processing entry files.
* @property {string|function(PathData, AssetInfo): string} [filename = '[name].js'] The file name of output file.
*/
/**
* @typedef {ModuleOptions} ModuleProps

@@ -79,22 +69,5 @@ * @property {boolean} [`inline` = false] Whether inline CSS should contain inline source map.

/**
* @typedef {Object} AssetEntryOptions
* @property {string} name The key of webpack entry.
* @property {string} file The output asset file with absolute path.
* @property {string} assetFile The output asset file with relative path by webpack output path.
* Note: the method compilation.emitAsset() use this file as key of assets object
* and save the file relative by output path, defined in webpack.options.output.path.
* @property {string|function(PathData, AssetInfo): string} filenameTemplate The filename template or function.
* @property {string} filename The asset filename.
* The template strings support only these substitutions: [name], [base], [path], [ext], [id], [contenthash], [contenthash:nn]
* See https://webpack.js.org/configuration/output/#outputfilename
* @property {string} request The full path of import file with query.
* @property {string} importFile The import file only w/o query.
* @property {string} outputPath
* @property {string} sourcePath
* @property {{name: string, type: string}} library Define the output a js file.
* See https://webpack.js.org/configuration/output/#outputlibrary
* @property {function(string, AssetInfo, Compilation): string} [postprocess = null] The post process for extracted content from entry.
* @property {function(): string|null =} extract
* @property {Array} resources
* @property {boolean} [verbose = false] Show an information by handles of the entry in a postprocess.
* @typedef {Object} ExtractJsOptions
* @property {boolean|string} [verbose = false] Show the information at processing entry files.
* @property {string|function(PathData, AssetInfo): string} [filename = '[name].js'] The file name of output file.
*/

@@ -118,5 +91,2 @@

class AssetCompiler {
/** @type {PluginOptions} */
options = {};
entryLibrary = {

@@ -127,12 +97,3 @@ name: 'return',

// the id to bind loader with data passed into template via entry.data
entryDataIndex = 1;
entryDataCache = new Map();
// webpack's options and modules
webpackContext = '';
webpackOutputPath = '';
// current entry point during dependency compilation
/** @type AssetEntryOptions */
/** @type AssetEntryOptions The current entry point during dependency compilation. */
currentEntryPoint;

@@ -144,26 +105,6 @@

constructor(options = {}) {
this.options = options;
this.enabled = this.options.enabled !== false;
this.verbose = this.options.verbose === true;
Options.init(options);
if (options.modules && !Array.isArray(options.modules)) {
optionModulesException(options.modules);
}
let extractCssOptions = extractCss(options.css);
const moduleExtractCssOptions = this.options.modules.find(
(item) => item.test.source === extractCssOptions.test.source
);
if (moduleExtractCssOptions) {
extractCssOptions = moduleExtractCssOptions;
} else {
this.options.modules.unshift(extractCssOptions);
}
this.options.extractCss = extractCssOptions;
this.options.extractJs = options.js || {};
// let know the loader that the plugin is being used
PluginService.init(this.options);
PluginService.init(Options);

@@ -215,59 +156,2 @@ // bind the instance context for using these methods as references in Webpack hooks

/**
* Entries defined in plugin options are merged with Webpack entry option.
*
* @param {{}} options The Webpack options where entry contains additional 'data' property.
*/
initializeWebpackEntry(options) {
let { entry } = options;
const pluginEntry = this.options.entry;
// check whether the entry in config is empty, defaults Webpack set structure: `{ main: {} }`,
if (Object.keys(entry).length === 1 && Object.keys(Object.entries(entry)[0][1]).length === 0) {
// set empty entry to avoid Webpack error
entry = {};
}
if (pluginEntry) {
for (const key in pluginEntry) {
const entry = pluginEntry[key];
if (entry.import == null) {
pluginEntry[key] = { import: [entry] };
continue;
}
if (!Array.isArray(entry.import)) {
entry.import = [entry.import];
}
}
options.entry = { ...entry, ...pluginEntry };
// the 'layer' entry property is only allowed when 'experiments.layers' is enabled
options.experiments.layers = true;
}
}
/**
* Get plugin module depend on type of source file.
*
* @param {string} sourceFile The source file of asset.
* @returns {ModuleOptions|undefined}
*/
getModule(sourceFile) {
return this.options.modules.find((module) => module.enabled !== false && module.test.test(sourceFile));
}
/**
* Whether the source file is an entry file.
*
* @param {string} sourceFile
* @return {boolean}
*/
isEntry(sourceFile) {
const [file] = sourceFile.split('?', 1);
return this.options.test.test(file);
}
/**
* Apply plugin.

@@ -277,44 +161,19 @@ * @param {{}} compiler

apply(compiler) {
if (!this.enabled) return;
if (!Options.isEnabled()) return;
this.initialize(compiler);
const { webpack } = compiler;
const { webpack, options } = compiler;
const webpackOutput = options.output;
const { extractJs } = this.options;
RawSource = webpack.sources.RawSource;
HotUpdateChunk = webpack.HotUpdateChunk;
// save using webpack options
this.webpackContext = options.context;
this.webpackOutputPath = webpackOutput.path || path.join(__dirname, 'dist');
Options.initWebpack(compiler.options);
Options.enableLibraryType(this.entryLibrary.type);
this.initialize(compiler);
// define js output filename
if (!webpackOutput.filename) {
webpackOutput.filename = '[name].js';
}
if (extractJs.filename) {
webpackOutput.filename = extractJs.filename;
} else {
extractJs.filename = webpackOutput.filename;
}
// resolve js filename by outputPath
if (extractJs.outputPath) {
const filename = extractJs.filename;
extractJs.filename = isFunction(filename)
? (pathData, assetInfo) => this.resolveOutputFilename(filename(pathData, assetInfo), extractJs.outputPath)
: this.resolveOutputFilename(extractJs.filename, extractJs.outputPath);
webpackOutput.filename = extractJs.filename;
}
Asset.init({
outputPath: this.webpackOutputPath,
publicPath: webpackOutput.publicPath,
outputPath: Options.webpackOptions.output.path,
publicPath: Options.webpackOptions.output.publicPath,
});
AssetResource.init(compiler);
AssetEntry.setWebpackOutputPath(this.webpackOutputPath);
AssetEntry.setWebpackOutputPath(Options.webpackOptions.output.path);

@@ -326,14 +185,2 @@ // clear caches by tests for webpack serve/watch

// enable library type
const libraryType = this.entryLibrary.type;
if (webpackOutput.enabledLibraryTypes.indexOf(libraryType) < 0) {
webpackOutput.enabledLibraryTypes.push(libraryType);
}
if (!this.options.sourcePath) this.options.sourcePath = this.webpackContext;
if (!this.options.outputPath) this.options.outputPath = this.webpackOutputPath;
// options.entry
this.initializeWebpackEntry(options);
// entry options

@@ -344,10 +191,4 @@ compiler.hooks.entryOption.tap(pluginName, this.afterProcessEntry);

compiler.hooks.watchRun.tap(pluginName, (compiler) => {
Options.initWatchMode();
PluginService.setWatchMode(true);
const { publicPath } = compiler.options.output;
if (publicPath == null || publicPath === 'auto') {
// By using watch/serve browsers not support an automatic publicPath in HMR script injected into inlined JS,
// the output.publicPath must be an empty string.
compiler.options.output.publicPath = '';
}
});

@@ -361,3 +202,3 @@

fs: normalModuleFactory.fs.fileSystem,
rootContext: this.webpackContext,
rootContext: Options.rootPath,
});

@@ -385,4 +226,7 @@

const [, entryDataId] = module.layer.split('=', 2);
loaderContext.entryData = this.entryDataCache.get(entryDataId);
loaderContext.data = this.entryDataCache.get(entryDataId);
// loaderContext.entryData = this.entryDataCache.get(entryDataId);
// loaderContext.data = this.entryDataCache.get(entryDataId);
loaderContext.entryData = AssetEntry.getData(entryDataId);
loaderContext.data = AssetEntry.getData(entryDataId);
}

@@ -421,64 +265,3 @@ });

afterProcessEntry(context, entries) {
const extensionRegexp = this.options.test;
for (let name in entries) {
const entry = entries[name];
let { filename: filenameTemplate, sourcePath, outputPath, postprocess, extract, verbose } = this.options;
const importFile = entry.import[0];
let request = importFile;
let [sourceFile] = importFile.split('?', 1);
const module = this.getModule(sourceFile);
if (!extensionRegexp.test(sourceFile) && !module) continue;
if (!entry.library) entry.library = this.entryLibrary;
if (module) {
if (module.hasOwnProperty('verbose')) verbose = module.verbose;
if (module.filename) filenameTemplate = module.filename;
if (module.sourcePath) sourcePath = module.sourcePath;
if (module.outputPath) outputPath = module.outputPath;
if (module.postprocess) postprocess = module.postprocess;
if (module.extract) extract = module.extract;
}
if (entry.filename) filenameTemplate = entry.filename;
if (!path.isAbsolute(sourceFile)) {
request = path.join(sourcePath, request);
sourceFile = path.join(sourcePath, sourceFile);
entry.import[0] = path.join(sourcePath, importFile);
}
/** @type {AssetEntryOptions} */
const assetEntryOptions = {
name,
filenameTemplate,
filename: undefined,
file: undefined,
request,
importFile: sourceFile,
sourcePath,
outputPath,
library: entry.library,
postprocess: isFunction(postprocess) ? postprocess : null,
extract: isFunction(extract) ? extract : null,
verbose,
};
if (entry.data) {
// IMPORTANT: when the entry contains same source file for many chunks, for example:
// {
// page1: { import: 'src/template.html', data: { title: 'A'} },
// page2: { import: 'src/template.html', data: { title: 'B'} },
// }
// add an unique identifier of the entry to execute a loader for all templates,
// otherwise Webpack call a loader only for the first template.
// See 'webpack/lib/NormalModule.js:identifier()'.
entry.layer = `__entryDataId=${this.entryDataIndex}`;
this.entryDataCache.set(`${this.entryDataIndex}`, entry.data);
this.entryDataIndex++;
}
AssetEntry.add(entry, assetEntryOptions);
}
AssetEntry.addEntries(entries, { entryLibrary: this.entryLibrary });
}

@@ -500,10 +283,8 @@

if (issuer && issuer.length > 0) {
const extractCss = this.options.extractCss;
if (extractCss.enabled && extractCss.test.test(issuer) && resourceFile.endsWith('.js')) {
// ignore runtime scripts of a loader, because a style can't have a javascript dependency
return false;
}
if (issuer) {
// ignore and exclude from compilation the runtime script of a css loader
if (Options.isStyle(issuer) && resourceFile.endsWith('.js')) return false;
const scriptFile = AssetScript.resolveFile(request);
if (scriptFile) {

@@ -514,3 +295,3 @@ const name = AssetScript.getUniqueName(scriptFile);

importFile: scriptFile,
filenameTemplate: this.options.extractJs.filename,
filenameTemplate: Options.getJs().filename,
context,

@@ -544,3 +325,3 @@ issuer,

filterAlternativeRequests(requests, options) {
return requests.filter((item) => !this.isEntry(item.request));
return requests.filter((item) => !Options.isEntry(item.request));
}

@@ -563,3 +344,3 @@

if (type === 'asset/inline' || type === 'asset') {
AssetInline.add(resource, issuer, this.isEntry(issuer));
AssetInline.add(resource, issuer, Options.isEntry(issuer));
}

@@ -620,3 +401,4 @@

renderManifest(result, { chunk, chunkGraph, outputOptions, codeGenerationResults }) {
const { compilation, verbose } = this;
const { compilation } = this;
const verbose = Options.isVerbose();

@@ -647,3 +429,3 @@ if (chunk instanceof HotUpdateChunk) return;

const [sourceFile] = sourceRequest.split('?', 1);
let issuerFile = !issuer || this.isEntry(issuer) ? entry.importFile : issuer;
let issuerFile = !issuer || Options.isEntry(issuer) ? entry.importFile : issuer;

@@ -654,9 +436,9 @@ if (module.type === 'javascript/auto') {

if (entry.importFile === issuer) {
const verbose = this.options.extractJs.verbose || entry.verbose;
const { verbose, outputPath } = Options.getJs();
if (verbose && issuerFile !== sourceFile) {
if ((verbose || entry.verbose) && issuerFile !== sourceFile) {
verboseList.add({
type: 'script',
sourceFile,
outputPath: this.options.extractJs.outputPath || this.webpackOutputPath,
outputPath,
});

@@ -718,3 +500,3 @@ }

// asset supported via the plugin module
const pluginModule = this.getModule(sourceFile);
const pluginModule = Options.getModule(sourceFile);
if (pluginModule == null) continue;

@@ -752,3 +534,3 @@

if (pluginModule.test.test(sourceFile)) {
assetFile = this.resolveOutputFilename(assetFile, pluginModule.outputPath);
assetFile = Options.resolveOutputFilename(assetFile, pluginModule.outputPath);
}

@@ -837,9 +619,7 @@

afterProcessAssets() {
const options = this.options;
const compilation = this.compilation;
const { compiler, assets } = compilation;
const { RawSource } = compiler.webpack.sources;
const afterProcess = typeof options.afterProcess === 'function' ? options.afterProcess : null;
if (options.extractComments !== true) {
if (!Options.isExtractComments()) {
AssetTrash.removeComments(compilation);

@@ -856,12 +636,5 @@ }

let newContent = this.afterProcess(compilation, { sourceFile, assetFile, source });
let res = Options.afterProcess(newContent || source, { sourceFile, assetFile });
if (afterProcess && assetFile.endsWith('.html')) {
try {
// TODO: test not yet documented experimental feature and rename it to other name
let result = afterProcess(newContent || source, { sourceFile, assetFile });
if (result) newContent = result;
} catch (err) {
throw new Error(err);
}
}
if (res != null) newContent = res;

@@ -924,3 +697,3 @@ if (newContent != null) {

require: Resolver.require,
// the `module.id` is required for `css-loader`, in module extractCss expected as source path
// the `module.id` is required for `css-loader`, in module extract CSS expected as the source path
module: { id: sourceFile },

@@ -1011,3 +784,3 @@ };

sourceFile,
outputPath: this.webpackOutputPath,
outputPath: Options.webpackOptions.output.path,
});

@@ -1035,24 +808,4 @@ break;

}
/**
* @param {string} filename The output filename.
* @param {string | null} outputPath The output path.
* @return {string}
*/
resolveOutputFilename(filename, outputPath) {
if (!outputPath) return filename;
let relativeOutputPath = path.isAbsolute(outputPath)
? path.relative(this.webpackOutputPath, outputPath)
: outputPath;
if (relativeOutputPath) {
if (isWin) relativeOutputPath = pathToPosix(relativeOutputPath);
filename = path.posix.join(relativeOutputPath, filename);
}
return filename;
}
}
module.exports = AssetCompiler;
const path = require('path');
const { isFunction } = require('./Utils');
const Options = require('./Options');
/**
* @typedef {Object} AssetEntryOptions
* @property {string} name The key of webpack entry.
* @property {string} file The output asset file with absolute path.
* @property {string} assetFile The output asset file with relative path by webpack output path.
* Note: the method compilation.emitAsset() use this file as key of assets object
* and save the file relative by output path, defined in webpack.options.output.path.
* @property {string|function(PathData, AssetInfo): string} filenameTemplate The filename template or function.
* @property {string} filename The asset filename.
* The template strings support only these substitutions: [name], [base], [path], [ext], [id], [contenthash], [contenthash:nn]
* See https://webpack.js.org/configuration/output/#outputfilename
* @property {string} request The full path of import file with query.
* @property {string} importFile The import file only w/o query.
* @property {string} outputPath
* @property {string} sourcePath
* @property {{name: string, type: string}} library Define the output a js file.
* See https://webpack.js.org/configuration/output/#outputlibrary
* @property {function(string, AssetInfo, Compilation): string} [postprocess = null] The post process for extracted content from entry.
* @property {function(): string|null =} extract
* @property {Array} resources
* @property {boolean|string} [verbose = false] Show an information by handles of the entry in a postprocess.
*/
class AssetEntry {

@@ -12,2 +36,6 @@ /** @type {Map<string, AssetEntryOptions>} */

// the id to bind loader with data passed into template via entry.data
static dataIndex = 1;
static data = new Map();
/**

@@ -36,7 +64,81 @@ * @param {string} outputPath The Webpack output path.

static getData(id) {
return this.data.get(id);
}
/**
* @param {Array<Object>} entries
* @param {Object} entryLibrary
*/
static addEntries(entries, { entryLibrary }) {
for (let name in entries) {
const entry = entries[name];
const importFile = entry.import[0];
let request = importFile;
let [sourceFile] = importFile.split('?', 1);
const module = Options.getModule(sourceFile);
let { filename: filenameTemplate, sourcePath, outputPath, postprocess, extract } = Options.get();
let verbose = Options.isVerbose();
if (!Options.isEntry(sourceFile) && !module) continue;
if (!entry.library) entry.library = entryLibrary;
if (module) {
if (module.hasOwnProperty('verbose')) verbose = Options.isTrue(module.verbose, false);
if (module.filename) filenameTemplate = module.filename;
if (module.sourcePath) sourcePath = module.sourcePath;
if (module.outputPath) outputPath = module.outputPath;
if (module.postprocess) postprocess = module.postprocess;
if (module.extract) extract = module.extract;
}
if (entry.filename) filenameTemplate = entry.filename;
if (!path.isAbsolute(sourceFile)) {
request = path.join(sourcePath, request);
sourceFile = path.join(sourcePath, sourceFile);
entry.import[0] = path.join(sourcePath, importFile);
}
/** @type {AssetEntryOptions} */
const assetEntryOptions = {
name,
filenameTemplate,
filename: undefined,
file: undefined,
request,
importFile: sourceFile,
sourcePath,
outputPath,
library: entry.library,
postprocess: isFunction(postprocess) ? postprocess : null,
extract: isFunction(extract) ? extract : null,
verbose,
};
if (entry.data) {
// IMPORTANT: when the entry contains same source file for many chunks, for example:
// {
// page1: { import: 'src/template.html', data: { title: 'A'} },
// page2: { import: 'src/template.html', data: { title: 'B'} },
// }
// add an unique identifier of the entry to execute a loader for all templates,
// otherwise Webpack call a loader only for the first template.
// See 'webpack/lib/NormalModule.js:identifier()'.
entry.layer = `__entryDataId=${this.dataIndex}`;
this.data.set(`${this.dataIndex}`, entry.data);
this.dataIndex++;
}
this.#add(entry, assetEntryOptions);
}
}
/**
* @param {{}} entry The webpack entry object.
* @param {AssetEntryOptions} assetEntryOptions
* @private
*/
static add(entry, assetEntryOptions) {
static #add(entry, assetEntryOptions) {
const { name, outputPath, filenameTemplate } = assetEntryOptions;

@@ -79,3 +181,3 @@ const relativeOutputPath = path.isAbsolute(outputPath)

// skip duplicate entries
if (this.inEntry(name, importFile)) return false;
if (this.#exists(name, importFile)) return false;

@@ -109,3 +211,3 @@ const entry = {

this.add(entry, assetEntryOptions);
this.#add(entry, assetEntryOptions);
this.compilationEntryNames.add(name);

@@ -141,4 +243,5 @@

* @return {boolean}
* @private
*/
static inEntry(name, file) {
static #exists(name, file) {
const entry = this.entryMap.get(name);

@@ -145,0 +248,0 @@ return entry && entry.importFile === file;

@@ -5,3 +5,3 @@ const { red, green, black } = require('ansis/colors');

const header = `\n${black.bgYellow`[${pluginName}] DEPRECATE`} `;
const header = `\n${black.bgYellow` ${pluginName} `}${black.bgAnsi(227)` DEPRECATE `} `;

@@ -8,0 +8,0 @@ const deprecateOptionExtractCss = () => {

const fs = require('fs');
const path = require('path');
const { red, green, cyan, cyanBright, yellow, white, blueBright } = require('ansis/colors');
const { green, cyan, cyanBright, yellow, white, blueBright, black } = require('ansis/colors');
const { pluginName } = require('../../config');
const header = `\n${red`[${pluginName}]`}`;
const header = `\n${black.bgRedBright` ${pluginName} `}`;
let lastError = null;

@@ -8,0 +8,0 @@

const { pluginName } = require('../../config');
const { pathRelativeByPwd, outToConsole, isFunction } = require('../Utils');
const {
green,
greenBright,
cyan,
cyanBright,
magenta,
yellowBright,
black,
gray,
ansi,
yellow,
} = require('ansis/colors');
const { green, greenBright, cyan, cyanBright, magenta, yellowBright, black, ansi, yellow } = require('ansis/colors');
const Asset = require('../Asset');
const grayBright = ansi(245);
const header = black.bgGreen`[${pluginName}]`;
const header = black.bgGreen` ${pluginName} `;

@@ -20,0 +9,0 @@ // max width of labels in first column

@@ -5,3 +5,3 @@ const { black, yellow, cyan, magenta } = require('ansis/colors');

const header = `\n${black.bgYellow`[${pluginName}] WARNING`} `;
const header = `\n${black.bgYellow` ${pluginName} `}${black.bgAnsi(227)` WARNING `} `;

@@ -8,0 +8,0 @@ const duplicateScriptWarning = (request, issuer) => {

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

*/
/** @typedef {import('Options')} PluginOptionInstance */
class PluginService {
/** @type PluginOptionInstance Provide to use the plugin option instance in the loader. */
static #options = null;
static used = false;
static options = null;
static contextCache = new Set();
static compiler = null;
static watchMode = false;
static watchMode;

@@ -20,7 +25,8 @@ /**

*
* @param {{}} options The options of the plugin.
* @param {PluginOptionInstance} options The plugin options instance.
*/
static init(options) {
this.used = true;
this.options = options;
this.#options = options;
this.watchMode = false;
}

@@ -36,21 +42,12 @@

/**
* Returns plugin options.
* Returns plugin options instance.
*
* @return {null}
* @return {PluginOptionInstance}
*/
static getOptions() {
return this.options;
return this.#options;
}
/**
* Return a list of resolve restrictions to restrict the paths that a request can be resolved on.
* @see https://webpack.js.org/configuration/resolve/#resolverestrictions
* @return {Array<RegExp|string>}
*/
static getStyleRestrictions() {
return this.options ? [this.options.extractCss?.test] : [];
}
/**
* Whether is the plugin used.
* Whether the plugin is defined in Webpack configuration.
* @return {boolean}

@@ -57,0 +54,0 @@ */

@@ -1,22 +0,4 @@

const path = require('path');
const { isWin, isFunction, pathRelativeByPwd, pathToPosix, parseQuery, outToConsole } = require('../Common/Helpers');
const { isWin, isFunction, workingDir, pathToPosix, parseQuery, outToConsole } = require('../Common/Helpers');
/**
* Return path of file relative by working directory.
*
* @param {string} file
* @return {string}
*/
const pathRelativeByPwd = (file) => {
if (file.startsWith(workingDir)) {
let relPath = path.relative(workingDir, file);
return path.extname(file) ? relPath : path.join(relPath, path.sep);
}
return file;
};
/**
* Parse resource path and raw query from request.

@@ -23,0 +5,0 @@ *

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