liferay-npm-bundler-preset-reactjs
Version:
liferay npm bundler preset react
381 lines (380 loc) • 14.8 kB
JavaScript
"use strict";
/**
* SPDX-FileCopyrightText: © 2020 Liferay, Inc. <https://liferay.com>
* SPDX-License-Identifier: LGPL-3.0-or-later
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Project = exports.ProjectType = void 0;
const child_process_1 = __importDefault(require("child_process"));
const dot_prop_1 = __importDefault(require("dot-prop"));
const fs_1 = __importDefault(require("fs"));
const merge_1 = __importDefault(require("merge"));
const path_1 = __importDefault(require("path"));
const read_json_sync_1 = __importDefault(require("read-json-sync"));
const resolve_1 = __importDefault(require("resolve"));
const file_path_1 = __importDefault(require("../file-path"));
const modules_1 = require("../modules");
const copy_1 = __importDefault(require("./copy"));
const jar_1 = __importDefault(require("./jar"));
const localization_1 = __importDefault(require("./localization"));
const misc_1 = __importDefault(require("./misc"));
const probe_1 = __importDefault(require("./probe"));
const rules_1 = __importDefault(require("./rules"));
const transform_1 = __importDefault(require("./transform"));
var probe_2 = require("./probe");
Object.defineProperty(exports, "ProjectType", { enumerable: true, get: function () { return probe_2.ProjectType; } });
/**
* Describes a standard JS Toolkit project.
*/
class Project {
/**
* @param projectDirPath project's path in native format
*/
constructor(projectDirPath) {
this.loadFrom(projectDirPath);
}
/**
* Get directories inside the project containing source files starting with
* `./` (so that they can be safely path.joined)
*/
get sources() {
if (this._sources === undefined) {
this._sources = dot_prop_1.default
.get(this._npmbundlerrc, 'sources', [])
.map((source) => source.startsWith('./') ? source : `./${source}`)
.map((source) => new file_path_1.default(source, { posix: true }));
}
return this._sources;
}
/**
* Get directory where files to be transformed live relative to
* `this.dir` and starting with `./` (so that it can be safely path.joined)
*/
get buildDir() {
if (this._buildDir === undefined) {
let dir = dot_prop_1.default.get(this._npmbundlerrc, 'output', this.jar.supported
? './build'
: './build/resources/main/META-INF/resources');
if (!dir.startsWith('./')) {
dir = `./${dir}`;
}
this._buildDir = new file_path_1.default(dir, { posix: true });
}
return this._buildDir;
}
/**
* Get absolute path to project's directory.
*/
get dir() {
return this._projectDir;
}
/**
* Get global plugins configuration.
*/
get globalConfig() {
const { _npmbundlerrc } = this;
return dot_prop_1.default.get(_npmbundlerrc, 'config', {});
}
/**
* Get project's parsed .npmbundlerrc file
*/
get npmbundlerrc() {
return this._npmbundlerrc;
}
/**
* Get project's parsed package.json file
*/
get pkgJson() {
return this._pkgJson;
}
/**
* Return the package manager that the project is using or null if it cannot
* be inferred.
*/
get pkgManager() {
if (this._pkgManager === undefined) {
let yarnLockPresent = fs_1.default.existsSync(this._projectDir.join('yarn.lock').asNative);
let pkgLockPresent = fs_1.default.existsSync(this._projectDir.join('package-lock.json').asNative);
// If both present act as if none was present
if (yarnLockPresent && pkgLockPresent) {
yarnLockPresent = pkgLockPresent = false;
}
if (yarnLockPresent) {
this._pkgManager = 'yarn';
}
else if (pkgLockPresent) {
this._pkgManager = 'npm';
}
else {
// If no file is found autodetect command availability
let yarnPresent = child_process_1.default.spawnSync('yarn', ['--version'], {
shell: true,
}).error === undefined;
let npmPresent = child_process_1.default.spawnSync('npm', ['--version'], {
shell: true,
}).error === undefined;
// If both present act as if none was present
if (yarnPresent && npmPresent) {
yarnPresent = npmPresent = false;
}
if (yarnPresent) {
this._pkgManager = 'yarn';
}
else if (npmPresent) {
this._pkgManager = 'npm';
}
}
// If nothing detected store null
if (this._pkgManager === undefined) {
this._pkgManager = null;
}
}
return this._pkgManager;
}
/**
* Get information about the preset in use
*/
get presetInfo() {
return this._presetInfo;
}
/**
* Get all available information about versions of plugins and presets used
* for the build.
* @return a Map where keys are package names
*/
get versionsInfo() {
if (this._versionsInfo === undefined) {
let map = new Map();
const putInMap = (packageName) => {
const pkgJsonPath = this.toolResolve(`${packageName}/package.json`);
const pkgJson = require(pkgJsonPath);
map.set(pkgJson.name, {
version: pkgJson.version,
path: path_1.default.relative(this.dir.asNative, path_1.default.dirname(pkgJsonPath)),
});
};
// Get bundler and me versions
putInMap('liferay-npm-bundler');
putInMap(path_1.default.join(__dirname, '../..'));
// Get preset version
const { _npmbundlerrc } = this;
const preset = _npmbundlerrc['preset'];
if (preset) {
const { pkgName, scope } = modules_1.splitModuleName(preset);
putInMap(scope ? `${scope}/${pkgName}` : pkgName);
}
map = new Map([...map, ...this.transform.versionsInfo]);
map = new Map([...map, ...this.rules.versionsInfo]);
this._versionsInfo = map;
}
return this._versionsInfo;
}
/**
* Reload the whole project from given directory. Especially useful for
* tests.
* @param projectPath
* project's path in native format (whether absolute or relative to cwd)
* @param configFilePath
* optional path to configuration file (relative to `projectPath` if not
* given as an absolute path)
*/
loadFrom(projectPath, configFilePath = '.npmbundlerrc') {
// First reset everything
this._buildDir = undefined;
this._configFile = undefined;
this._npmbundlerrc = undefined;
this._pkgJson = undefined;
this._pkgManager = undefined;
this._projectDir = undefined;
this._sources = undefined;
this._toolsDir = undefined;
// Set significant directories
this._projectDir = new file_path_1.default(path_1.default.resolve(projectPath));
this._configFile = new file_path_1.default(path_1.default.isAbsolute(configFilePath)
? configFilePath
: path_1.default.resolve(path_1.default.join(projectPath, configFilePath)));
this._toolsDir = this._projectDir;
// Load configuration files
this._loadPkgJson();
this._loadNpmbundlerrc();
// Initialize subdomains
this.copy = new copy_1.default(this);
this.jar = new jar_1.default(this);
this.l10n = new localization_1.default(this);
this.misc = new misc_1.default(this);
this.probe = new probe_1.default(this);
this.rules = new rules_1.default(this);
this.transform = new transform_1.default(this);
}
/**
* Requires a module in the context of the project (as opposed to the
* context of the calling package which would just use a normal `require()`
* call).
* @param moduleName
*/
require(moduleName) {
return require(this.resolve(moduleName));
}
/**
* Resolves a module in the context of the project (as opposed to the
* context of the calling package which would just use a normal
* `require.resolve()` call).
* @param moduleName
*/
resolve(moduleName) {
return resolve_1.default.sync(moduleName, {
basedir: this.dir.asNative,
});
}
/**
* Set program arguments so that some of them can be parsed as if they were
* `.npmbundlerrc` options.
*/
set argv(argv) {
const { _npmbundlerrc } = this;
if (argv.config) {
this.loadFrom('.', argv.config);
}
if (argv['create-jar']) {
_npmbundlerrc['create-jar'] = true;
}
if (argv['dump-report']) {
_npmbundlerrc['dump-report'] = true;
}
}
/**
* Requires a tool module in the context of the project (as opposed to the
* context of the calling package which would just use a normal `require()`
* call).
*
* @remarks
* This looks in the `.npmbundlerrc` preset before calling the standard
* {@link require} method.
*
* @param moduleName
* @throws if module is not found
*/
toolRequire(moduleName) {
return require(this.toolResolve(moduleName));
}
/**
* Resolves a tool module in the context of the project (as opposed to the
* context of the calling package which would just use a normal
* `require.resolve()` call).
*
* @remarks
* This looks in the `.npmbundlerrc` preset before calling the standard
* {@link require} method.x
*
* @param moduleName
* @throws if module is not found
*/
toolResolve(moduleName) {
try {
return resolve_1.default.sync(moduleName, {
basedir: this._toolsDir.asNative,
});
}
catch (err) {
return this.resolve(moduleName);
}
}
_getAutopreset() {
const { dependencies = {}, devDependencies = {} } = this._pkgJson;
const autopresets = Object.keys({
...dependencies,
...devDependencies,
}).reduce((autopresets, pkgName) => {
try {
const { dependencies } = this.require(pkgName + '/package.json');
if (!dependencies || !dependencies['liferay-npm-bundler']) {
return autopresets;
}
const mainModulePath = this.resolve(pkgName);
if (!mainModulePath.toLowerCase().endsWith('.json')) {
return autopresets;
}
autopresets.push(pkgName);
}
catch (err) {
// ignore
}
return autopresets;
}, []);
if (autopresets.length > 1) {
throw new Error('Multiple autopreset dependencies found in project ' +
`(${autopresets}): please remove the invalid ones or ` +
'explicitly define the preset to be used in the ' +
'.npmbundlerrc file');
}
return autopresets.length ? autopresets[0] : null;
}
_loadNpmbundlerrc() {
const npmbundlerrcPath = this._configFile.asNative;
const config = fs_1.default.existsSync(npmbundlerrcPath)
? read_json_sync_1.default(npmbundlerrcPath)
: {};
// Apply preset if necessary
let presetFilePath;
const autopreset = this._getAutopreset();
if (config.preset === undefined && autopreset) {
// If an autopreset is found and none is configured, use it
this._presetInfo = {
isAutopreset: true,
name: autopreset,
};
this._toolsDir = new file_path_1.default(path_1.default.dirname(this.resolve(`${autopreset}/package.json`)));
presetFilePath = this.resolve(autopreset);
}
else if (config.preset === undefined) {
// If no preset was found, use the default one
this._presetInfo = {
isAutopreset: false,
name: 'liferay-npm-bundler-preset-standard',
};
this._toolsDir = new file_path_1.default(path_1.default.dirname(require.resolve('liferay-npm-bundler-preset-standard/package.json')));
presetFilePath = require.resolve('liferay-npm-bundler-preset-standard');
}
else if (config.preset === '' || config.preset === false) {
// don't load preset
this._presetInfo = undefined;
}
else {
// If a preset is configured, use it
this._presetInfo = {
isAutopreset: false,
name: config.preset,
};
const { pkgName, scope } = modules_1.splitModuleName(config.preset);
const presetPkgJsonFilePath = this.resolve(scope
? `${scope}/${pkgName}/package.json`
: `${pkgName}/package.json`);
this._toolsDir = new file_path_1.default(path_1.default.dirname(presetPkgJsonFilePath));
presetFilePath = this.resolve(config.preset);
}
// Load preset configuration
if (presetFilePath) {
const originalConfig = { ...config };
Object.assign(config, merge_1.default.recursive(read_json_sync_1.default(presetFilePath), originalConfig));
}
// Resolve symbolic links in toolsDir so that we may test things locally
while (fs_1.default.lstatSync(this._toolsDir.asNative).isSymbolicLink()) {
const linkTarget = fs_1.default.readlinkSync(this._toolsDir.asNative);
this._toolsDir = new file_path_1.default(path_1.default.isAbsolute(linkTarget)
? linkTarget
: this._toolsDir.dirname().join(linkTarget).asNative);
}
this._npmbundlerrc = config;
}
_loadPkgJson() {
const pkgJsonPath = this.dir.join('package.json').asNative;
this._pkgJson = fs_1.default.existsSync(pkgJsonPath)
? read_json_sync_1.default(pkgJsonPath)
: {};
}
}
exports.Project = Project;
exports.default = new Project('.');