UNPKG

liferay-npm-bundler-preset-reactjs

Version:

liferay npm bundler preset react

381 lines (380 loc) 14.8 kB
"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('.');