@enonic/react4xp
Version:
Build tools for React4xp
369 lines (357 loc) • 13.7 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/webpack.config.globals.ts
var webpack_config_globals_exports = {};
__export(webpack_config_globals_exports, {
default: () => webpack_config_globals_default
});
module.exports = __toCommonJS(webpack_config_globals_exports);
var import_fs2 = require("fs");
var import_path = require("path");
var import_chunks_2_json_webpack_plugin = __toESM(require("chunks-2-json-webpack-plugin"));
// src/constants.runtime.ts
var GLOBALS_FILENAME = "globals.json";
var R4X_TARGETSUBDIR = "r4xAssets";
// src/constants.buildtime.ts
var DIR_PATH_RELATIVE_SRC_MAIN_RESOURCES = "src/main/resources";
var DIR_PATH_RELATIVE_SRC_R4X = `${DIR_PATH_RELATIVE_SRC_MAIN_RESOURCES}/react4xp`;
var DIR_PATH_RELATIVE_SRC_SITE = `${DIR_PATH_RELATIVE_SRC_MAIN_RESOURCES}/site`;
var DIR_PATH_RELATIVE_BUILD_RESOURCES_MAIN = "build/resources/main";
var DIR_PATH_RELATIVE_BUILD_LIB_R4X = `${DIR_PATH_RELATIVE_BUILD_RESOURCES_MAIN}/lib/enonic/react4xp`;
var DIR_PATH_RELATIVE_BUILD_ASSETS_R4X = `${DIR_PATH_RELATIVE_BUILD_RESOURCES_MAIN}/${R4X_TARGETSUBDIR}`;
var GLOBALS_DEFAULT = {
react: "React",
"react-dom": "ReactDOM",
"react-dom/server": "ReactDOMServer",
"html-react-parser": "HTMLReactParser"
// Adding it to globals to make sure we use server-side version of html-dom-parser dependency
};
var FILE_NAME_R4X_CONFIG_JS = "react4xp.config.js";
// src/globals/generateTempES6SourceAndGetFilename.ts
var import_fs = require("fs");
// src/util/isObject.ts
var isObject = (value) => Object.prototype.toString.call(value).slice(8, -1) === "Object";
// src/util/isString.ts
var isString = (value) => typeof value === "string" || value instanceof String;
// src/globals/generateTempES6SourceAndGetFilename.ts
function generateTempES6SourceAndGetFilename(globals, outputFileName) {
if (typeof outputFileName !== "string" || (outputFileName || "").trim() === "") {
console.warn(`${__filename} - Skipping generation of the globals chunk:
The outputFileName parameter must be a non-empty string: ${JSON.stringify(
outputFileName,
null,
2
)}`);
return null;
}
let globalsObj;
if (isString(globals)) {
globalsObj = JSON.parse(globals);
} else if (isObject(globals)) {
globalsObj = JSON.parse(JSON.stringify(globals));
}
if (!globalsObj || !isObject(globalsObj) || //Array.isArray(globalsObj) ||
Object.keys(globalsObj).length < 1) {
console.warn(`${__filename} - Skipping generation of the globals chunk:
The globals parameter must be an object (or JSON-string object) with at least one entry: ${JSON.stringify(
globalsObj,
null,
2
)}`);
return null;
}
let globalsImports = "";
let globalsExports = "";
Object.keys(globalsObj).forEach((key) => {
globalsImports += `import ${globalsObj[key]} from '${key}';
`;
});
if (globalsObj["react-dom"]) {
globalsImports += `import * as ReactDOMClient from 'react-dom/client';
`;
}
globalsImports += `import {getPublicPath} from './index.js';
`;
Object.keys(globalsObj).forEach((key) => {
const globalName = globalsObj[key];
if (key === "react-dom" && globalName === "ReactDOM") {
globalsExports += ` globalThis.${globalName} = Object.assign({}, ${globalName}, ReactDOMClient);
`;
} else {
globalsExports += ` globalThis.${globalName} = ${globalName};
`;
}
});
globalsExports += `
if (typeof document !== "undefined") {
globalThis.__R4XP_PUBLIC_PATH__ = getPublicPath("${process.env.R4X_APP_NAME}");
}
`;
const globalsES6 = `// AUTO-GENERATED by ${__filename}
${globalsImports}
(function() {
${globalsExports}} )();
`;
(0, import_fs.writeFileSync)(outputFileName, globalsES6);
return outputFileName;
}
// src/util/makeVerboseLogger.ts
var import_q_i = require("q-i");
var makeVerboseLogger = (VERBOSE) => VERBOSE ? (item, label, stringify = false) => {
if (typeof item === "object") {
if (label) {
console.log(label + ":");
}
(0, import_q_i.print)(item, { maxItems: Infinity });
} else if (stringify) {
console.log((label ? label + " " : "") + "(" + typeof item + "): " + JSON.stringify(item));
} else {
console.log((label ? label + ": " : "") + item);
}
} : () => {
};
// src/util/webpackLogLevel.ts
function webpackLogLevel(r4xBuildLogLevel = "LIFECYCLE" /* LIFECYCLE */) {
switch (r4xBuildLogLevel) {
case "QUIET" /* QUIET */:
return "none" /* NONE */;
// disable logging
case "ERROR" /* ERROR */:
return "error" /* ERROR */;
// errors only
case "WARN" /* WARN */:
return "warn" /* WARN */;
// errors and warnings only
case "LIFECYCLE" /* LIFECYCLE */:
return "info" /* INFO */;
// errors, warnings, and info messages
case "INFO" /* INFO */:
return "log" /* LOG */;
// errors, warnings, info messages, log messages, groups, clears. Collapsed groups are displayed in a collapsed state
case "DEBUG" /* DEBUG */:
return "verbose" /* VERBOSE */;
// log everything except debug and trace
default:
console.warn(`Unknown log level '${r4xBuildLogLevel}' falling back to default log level 'info'`);
return "info" /* INFO */;
}
}
// src/webpack.config.globals.ts
var import_filemanager_webpack_plugin = __toESM(require("filemanager-webpack-plugin"));
var webpack_config_globals_default = () => {
const R4X_DIR_PATH_ABSOLUTE_PROJECT = process.env.R4X_DIR_PATH_ABSOLUTE_PROJECT;
if (!(0, import_path.isAbsolute)(R4X_DIR_PATH_ABSOLUTE_PROJECT)) {
throw new Error(`System environment variable R4X_DIR_PATH_ABSOLUTE_PROJECT:${R4X_DIR_PATH_ABSOLUTE_PROJECT} not an absolute path!`);
}
const DIR_PATH_ABSOLUTE_BUILD_SYSTEM = (0, import_path.resolve)(__dirname, "..");
const DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X = (0, import_path.join)(R4X_DIR_PATH_ABSOLUTE_PROJECT, DIR_PATH_RELATIVE_BUILD_ASSETS_R4X);
const WEBPACK_MODE = process.env.NODE_ENV || "production";
const DEVMODE = WEBPACK_MODE !== "production";
const LOG_LEVEL = webpackLogLevel(process.env.R4X_BUILD_LOG_LEVEL);
const verboseLog = makeVerboseLogger([
"log" /* LOG */,
"verbose" /* VERBOSE */
].includes(LOG_LEVEL));
verboseLog(DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X, "DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X", 1);
let GLOBALS = GLOBALS_DEFAULT;
verboseLog(GLOBALS, "GLOBALS");
const FILE_PATH_ABSOLUTE_R4X_CONFIG_JS = (0, import_path.join)(R4X_DIR_PATH_ABSOLUTE_PROJECT, FILE_NAME_R4X_CONFIG_JS);
try {
const configJsonStats = (0, import_fs2.statSync)(FILE_PATH_ABSOLUTE_R4X_CONFIG_JS);
if (configJsonStats.isFile()) {
const config = require(FILE_PATH_ABSOLUTE_R4X_CONFIG_JS);
if (config.globals) {
GLOBALS = Object.assign(config.globals, GLOBALS);
}
}
verboseLog(GLOBALS, "GLOBALS");
} catch (e) {
console.info(`${FILE_PATH_ABSOLUTE_R4X_CONFIG_JS} not found.`);
}
const tempFileName = generateTempES6SourceAndGetFilename(
GLOBALS,
(0, import_path.join)(__dirname, "_AUTOGENERATED_tmp_global_.es6")
);
const entry = tempFileName ? { globals: tempFileName } : {};
const plugins = tempFileName ? [
new import_filemanager_webpack_plugin.default({
events: {
onStart: {
mkdir: [
DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X
// Chunks2json fails without this (when using npm explore)
]
}
}
}),
// // @ts-expect-error
/*new CoreWebPlugin({
browsers: {
chrome: "63",
firefox: "57",
edge: "18",
opera: "57",
safari: "12",
ie: "11",
}
}),*/
new import_chunks_2_json_webpack_plugin.default({
outputDir: DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X,
filename: GLOBALS_FILENAME
})
] : void 0;
return {
context: R4X_DIR_PATH_ABSOLUTE_PROJECT,
// Used as default for resolve.roots
devtool: DEVMODE ? false : "source-map",
entry,
mode: WEBPACK_MODE,
module: {
rules: [{
test: /\.((jt)sx?|(es6?))$/,
// js, ts, jsx, tsx, es, es6
// I don't think we can exclude much, everything must be able to run:
// * server-side (Nashorn/Graal-JS) and
// * client-side (Browsers).
//exclude: /node_modules/,
// It takes time to transpile, if you know they don't need
// transpilation to run in Enonic XP (Nashorn/Graal-JS) you may list
// them here:
exclude: [
/[\\/]node_modules[\\/]core-js/,
// will cause errors if they are transpiled by Babel
// /[\\/]node_modules[\\/]react[\\/]/, // TODO Perhaps react don't need to be transpiled
// /[\\/]node_modules[\\/]react-dom[\\/]/, // TODO Perhaps react-dom don't need to be transpiled
/[\\/]node_modules[\\/]webpack[\\/]buildin/
// will cause errors if they are transpiled by Babel
],
use: [{
loader: "builtin:swc-loader",
options: {
jsc: {
// https://swc.rs/docs/configuration/compilation#jscexternalhelpers
// externalHelpers: true,
parser: {
dynamicImport: false,
jsx: true,
syntax: "typescript",
tsx: true
},
// target: 'es2015',
transform: {
react: {
runtime: "automatic",
development: DEVMODE,
// $RefreshReg$ is not defined
// refresh: DEVMODE,
refresh: false
}
}
},
minify: !DEVMODE,
// module: {
// type: 'commonjs'
// },
sourceMaps: !DEVMODE
}
}]
// use
}]
// rules
},
// module
optimization: {
minimize: !DEVMODE,
usedExports: !DEVMODE
// Disable slow tree-shaking in dev mode
},
output: {
path: DIR_PATH_ABSOLUTE_BUILD_ASSETS_R4X,
// <-- Sets the base url for plugins and other target dirs.
filename: DEVMODE ? "[name].js" : "[name].[contenthash].js",
environment: {
arrowFunction: false,
bigIntLiteral: false,
const: false,
destructuring: false,
dynamicImport: false,
forOf: false,
module: false
}
},
// output
performance: {
hints: false
},
plugins,
resolve: {
alias: {
// Graalvm works with server-side version only!
"html-dom-parser": [
(0, import_path.resolve)(R4X_DIR_PATH_ABSOLUTE_PROJECT, "node_modules/html-dom-parser/lib/server/html-to-dom.js"),
(0, import_path.resolve)(DIR_PATH_ABSOLUTE_BUILD_SYSTEM, "node_modules/html-dom-parser/lib/server/html-to-dom.js")
]
},
extensions: [".ts", ".tsx", ".es6", ".es", ".jsx", ".js", ".json"],
modules: [
// Tell webpack what directories should be searched when resolving
// modules.
// Absolute and relative paths can both be used, but be aware that they
// will behave a bit differently.
// A relative path will be scanned similarly to how Node scans for
// node_modules, by looking through the current directory as well as its
// ancestors (i.e. ./node_modules, ../node_modules, and on).
// With an absolute path, it will only search in the given directory.
// To resolve node_modules installed under the app
(0, import_path.resolve)(R4X_DIR_PATH_ABSOLUTE_PROJECT, "node_modules"),
// To resolve node_modules installed under the build system
(0, import_path.resolve)(DIR_PATH_ABSOLUTE_BUILD_SYSTEM, "node_modules")
//'node_modules'
]
/*roots: [ // Works, but maybe modules is more specific
// A list of directories where requests of server-relative URLs
// (starting with '/') are resolved, defaults to context configuration
// option. On non-Windows systems these requests are resolved as an
// absolute path first.
R4X_DIR_PATH_ABSOLUTE_PROJECT, // same as context
DIR_PATH_ABSOLUTE_BUILD_SYSTEM
],*/
},
// resolve
stats: {
colors: true,
hash: false,
logging: LOG_LEVEL,
modules: false,
moduleTrace: false,
timings: false,
version: false
}
// stats
};
};