/**
* @file src/exports/output.js
* @copyright @spmhome @_2025
* @author Scott Meesseman @spmeesseman
*
* @see {@link [webpack.js.org/output](https://webpack.js.org/configuration/output)}
*
*//** */
const { TestsChunk } = require("../utils/regex");
const WpwWebpackExport = require("./base");
/**
* @augments WpwWebpackExport
*/
class WpwOutputExport extends WpwWebpackExport
{
/**
* @param {WpwExportOptions} options
*/
constructor(options)
{
super(options);
this.buildOptions = /** @type {WpwBuildOptionsExportConfig<"output">} */(this.buildOptions); // reset for typings
}
/**
* @override
*/
static create = WpwOutputExport.wrap.bind(this);
/**
* @override
* @param {WpwBuild} build
*/
app(build)
{
const name = "[name]",
ext = this.outputExt,
hashEnabled = !!build.options.hash?.enabled;
build.logger.write("output rc configuration:", 1);
build.logger.values([
[ "extension", ext ], [ "filename", `${name}${ext}` ], [ "output path", build.wpc.output.path ]
], 1, " ");
this._obj_.apply(build.wpc.output,
{
filename: (/** @type {WebpackPathDataOutput} */data, /** @type {WebpackAssetInfo | undefined} */_info) =>
{
const hashedName = hashEnabled && !TestsChunk.test(data.chunk.name || "");
return `${name}${hashedName ? ".[contenthash]" : ""}${ext}`;
}
});
if (hashEnabled && (build.options.hash.emitNoHash || build.options.hash.emitAppNoHash))
{
build.logger.write("no-hash copy option enabled, reset output path to virtual", 3);
build.logger.value(" new path", build.virtualEntry.dirBuild, 3);
this._obj_.apply(build.wpc.output, { path: build.virtualEntry.dirBuild });
}
}
/**
* @override
* @param {WpwBuild} build
*/
base(build)
{
this._obj_.apply(build.wpc.output,
{
filename: "[name].js",
iife: !build.isModule,
module: build.isModule,
compareBeforeEmit: true,
path: build.getDistPath(),
hashDigest: this.buildOptions.hashDigest,
hashFunction: this.buildOptions.hashFunction,
chunkFormat: build.isModule ? "module" : undefined,
hashDigestLength: this.buildOptions.hashLength || 16,
libraryTarget: this.getLibraryType() // || "commonjs2"
});
}
/**
* @override
* @param {WpwBuild} build
*/
baseDone(build)
{
// if (!build.isWeb || build.wpc.output.libraryTarget === "umd") {
if (build.wpc.output.libraryTarget === "umd") {
build.wpc.output.globalObject = "this";
}
else if (build.isWebApp || build.isWebWorker) {
build.wpc.output.globalObject = "self";
}
else if (build.isWeb) {
build.wpc.output.globalObject = "globalThis";
}
else {
build.wpc.output.globalObject = "global";
}
}
/**
* @private
* @param {WpwBuild} build
*/
docs(build)
{
if (build.options.doc.output)
{
const o = build.wpc.output;
o.path = o.path.replace(new RegExp(`\\/${this._rgx_.escapeRegExp(build.options.doc.output)}$`), "");
}
}
/**
* @override
* @param {WpwBuild} build
*/
doxygen(build)
{
this.docs(build);
}
/**
* @override
* @param {WpwBuild} build
*/
extjsdoc(build)
{
this.docs(build);
}
/**
* @private
* @returns {WebpackLibrary}
* @throws {SpmhError}
*/
getLibraryType()
{
const b = this.build;
/** @type {WebpackLibrary} */
let libType = "global";
if (b.isAnyAppOrLib)
{
const checkTypes = [ "amd", "umd", "jsonp", "system" ];
if (checkTypes.includes(this.build.wpc.externalsType) && !checkTypes.includes(libType))
{
throw this.addMessage({
code: this.MsgCode.ERROR_CONFIG_INVALID_EXPORTS,
message: `library type (${libType}) must be == externals type '${this.build.wpc.externalsType}' `
});
}
if (checkTypes.includes(this.build.wpc.externalsType))
{
b.logger.write(`set output library type == externals type '${libType}'`, 2);
libType = /** @type { "amd" | "umd" | "jsonp" | "system"} */(this.build.wpc.externalsType);
b.library = libType;
}
else // if (!isWebpackLibrary(libType))
{
libType = b.library || "commonjs2";
b.logger.write(`set output library type to '${libType}'`, 2);
}
}
return libType;
}
/**
* @override
* @param {WpwBuild} build
*/
jsdoc(build)
{
this.docs(build);
}
/**
* @override
* @param {WpwBuild} build
*/
lib(build)
{
this.app(build);
this._obj_.apply(this.build.wpc.output,
{
enabledLibraryTypes: [
this.build.wpc.output.libraryTarget
],
library: {
type: this.build.wpc.output.libraryTarget
}
});
}
/**
* @override
* @param {WpwBuild} build
*/
plugin(build) { this.app(build); }
/**
* @override
*/
resource() {}
/**
* @override
*/
schema() {}
/**
* @override
* @param {WpwBuild} build
*/
script(build)
{
if (build.options.script.emitType === "vbuild" || build.options.script.emitType === "vdist") {
this._obj_.apply(build.wpc.output, { path: build.virtualEntry.dirBuild });
}
}
/**
* @override
*/
tests() {}
/**
* @override
*/
types() {}
/**
* @override
* @param {WpwBuild} build
*/
webapp(build)
{
if (build.options.hash?.enabled && (build.options.hash.emitNoHash || build.options.hash.emitAppNoHash))
{
build.wpc.output.path = build.virtualEntry.dirBuild;
}
this._obj_.apply(build.wpc.output,
{
// clean: build.clean ? { keep: /(img|font|readme|walkthrough)[\\/]/ } : undefined,
publicPath: process.env.AP_WWW_ASSET_PATH || process.env.AP_WWW_PUBLIC_PATH || "/public",
filename: (/** @type {WebpackPathDataOutput} */data, /** @type {WebpackAssetInfo | undefined} */_info) =>
{
let name = `${data.chunk.name}${build.options.hash?.enabled ? ".[contenthash]" : ""}`;
if (build.options.web?.camelToDash)
{
name = name.replace(/[a-z]+([A-Z])/g, (substr, token) => substr.replace(token, "-" + token.toLowerCase()));
build.logger.write(
` convert asset name to '${name}' [from ${data.chunk.name}]`, 2
);
}
return `${build.options.web?.jsDirectory ? "js/" : ""}${name}${this.outputExt}`;
}
});
if (build.options.web?.publicPath)
{
build.logger.write(` set rc configured publicPath to '${build.options.web.publicPath}'`, 3);
if (this._types_.isString(build.wpc.output.publicPath) && !build.wpc.output.publicPath.endsWith("/")) {
build.wpc.output.publicPath += "/";
}
build.wpc.output.publicPath = build.options.web.publicPath;
}
else if (build.options.vsceiso?.enabled)
{
build.logger.write(" set publicPath to '#{webroot}/' for vsc build", 3);
build.wpc.output.publicPath = "#{webroot}/";
}
}
}
module.exports = WpwOutputExport.create;