/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ // Rollup configuration // GENERATED BY Bazel const buildOptimizer = require( 'npm/node_modules/@angular-devkit/build-optimizer/src/build-optimizer/rollup-plugin.js'); const nodeResolve = require('rollup-plugin-node-resolve'); const sourcemaps = require('rollup-plugin-sourcemaps'); const commonjs = require('rollup-plugin-commonjs'); const path = require('path'); const fs = require('fs'); function log_verbose(...m) { // This is a template file so we use __filename to output the actual filename if (!!process.env['VERBOSE_LOGS']) console.error(`[${path.basename(__filename)}]`, ...m); } const workspaceName = 'TMPL_workspace_name'; const useBuildOptimzier = TMPL_build_optimizer; const rootDir = 'TMPL_root_dir'; const bannerFile = TMPL_banner_file; const stampData = TMPL_stamp_data; const moduleMappings = TMPL_module_mappings; const nodeModulesRoot = 'TMPL_node_modules_root'; const ivyEnabled = TMPL_ivy_enabled; log_verbose(`running with cwd: ${process.cwd()} workspaceName: ${workspaceName} useBuildOptimzier: ${useBuildOptimzier} rootDir: ${rootDir} bannerFile: ${bannerFile} stampData: ${stampData} moduleMappings: ${JSON.stringify(moduleMappings)} nodeModulesRoot: ${nodeModulesRoot} ivyEnabled: ${ivyEnabled} `); function fileExists(filePath) { try { return fs.statSync(filePath).isFile(); } catch (e) { return false; } } // This resolver mimics the TypeScript Path Mapping feature, which lets us resolve // modules based on a mapping of short names to paths. function resolveBazel( importee, importer, baseDir = process.cwd(), resolve = require.resolve, root = rootDir) { log_verbose(`resolving '${importee}' from ${importer}`); function resolveInRootDir(importee) { function tryImportee(importee) { var candidate = path.join(baseDir, root, importee); log_verbose(`try to resolve '${importee}' at '${candidate}'`); try { var result = resolve(candidate); return result; } catch (e) { return undefined; } } // Attempt in the following order {importee}.mjs, {importee}/index.mjs, // {importee}, {importee}.js, {importee}/index.js. If an .mjs file is // available it should be resolved as rollup cannot handle the .js files // generated by ts_library as they are not esm. When rolling up esm5 files // these are re-rooted so it is not an issue. // TODO(gregmagolan): clean this up in the future as the .mjs es2015 outputs // along side the .js es5 outputs from ts_library creates this unusual situation for // which we can't rely on standard node module resolution to do the right thing. // In the future ts_library (or equivalent) should only produce a single flavor of // output and ng_rollup_bundle should also just use the use the vanilla rollup_bundle // rule without the need for a custom bazel resolver. return tryImportee(`${importee}.mjs`) || tryImportee(`${importee}/index.mjs`) || tryImportee(importee) || tryImportee(`${importee}.js`) || tryImportee(`${importee}/index.js`); } // Since mappings are always in POSIX paths, when comparing the importee to mappings // we should normalize the importee. // Having it normalized is also useful to determine relative paths. const normalizedImportee = importee.replace(/\\/g, '/'); // If import is fully qualified then resolve it directly if (fileExists(importee)) { log_verbose(`resolved fully qualified '${importee}'`); return importee; } var resolved; if (normalizedImportee.startsWith('./') || normalizedImportee.startsWith('../')) { // relative import if (importer) { let importerRootRelative = path.dirname(importer); const relative = path.relative(path.join(baseDir, root), importerRootRelative); if (!relative.startsWith('.')) { importerRootRelative = relative; } resolved = path.join(importerRootRelative, importee); } else { throw new Error('cannot resolve relative paths without an importer'); } if (resolved) resolved = resolveInRootDir(resolved); } if (!resolved) { // possible workspace import or external import if importee matches a module // mapping for (const k in moduleMappings) { if (normalizedImportee == k || normalizedImportee.startsWith(k + '/')) { // replace the root module name on a mappings match // note that the module_root attribute is intended to be used for type-checking // so it uses eg. "index.d.ts". At runtime, we have only index.js, so we strip the // .d.ts suffix and let node require.resolve do its thing. var v = moduleMappings[k].replace(/\.d\.ts$/, ''); const mappedImportee = path.join(v, normalizedImportee.slice(k.length + 1)); log_verbose(`module mapped '${importee}' to '${mappedImportee}'`); resolved = resolveInRootDir(mappedImportee); if (resolved) break; } } } if (!resolved) { // workspace import const userWorkspacePath = path.relative(workspaceName, importee); resolved = resolveInRootDir(userWorkspacePath.startsWith('..') ? importee : userWorkspacePath); } if (resolved) { log_verbose(`resolved to ${resolved}`); } else { log_verbose(`allowing rollup to resolve '${importee}' with node module resolution`); } return resolved; } // We make mainFields match what was the default for plugin-node-resolve <4.2.0 // when mainFields was introduced. Resolving to 'browser' or 'es2015' first breaks // some of the benchmarks such as `//modules/benchmarks/src/expanding_rows:perf_chromium-local`. // See https://app.circleci.com/jobs/github/angular/angular/507444 && // https://app.circleci.com/jobs/github/angular/angular/507442 for affected tests. const mainFields = ['module', 'main']; const ngccMainFields = mainFields.map(f => `${f}_ivy_ngcc`); let plugins = [ { name: 'resolveBazel', resolveId: resolveBazel, }, nodeResolve({ // If Ivy is enabled, we need to make sure that the module resolution prioritizes ngcc // processed entry-point fields. Ngcc adds special fields to `package.json` files of // modules that have been processed. Prioritizing these fields matches the Angular CLIs // behavior for supporting Ivy. We need to support ngcc because `ng_rollup_bundle` rule is // shared with other repositories that consume Angular from NPM (w/ ngcc). // https://github.com/angular/angular-cli/blob/1a1ceb609b9a87c4021cce3a6f0fc6d167cd09d2/packages/ngtools/webpack/src/angular_compiler_plugin.ts#L918-L920 mainFields: ivyEnabled ? [...ngccMainFields, ...mainFields] : mainFields, jail: process.cwd(), customResolveOptions: {moduleDirectory: nodeModulesRoot} }), commonjs({ignoreGlobal: true}), sourcemaps(), ]; if (useBuildOptimzier) { plugins = [ buildOptimizer.default({ sideEffectFreeModules: [ '.esm5/packages/core/src', '.esm5/packages/common/src', '.esm5/packages/compiler/src', '.esm5/packages/platform-browser/src', ] }), ].concat(plugins); } let banner = ''; if (bannerFile) { banner = fs.readFileSync(bannerFile, {encoding: 'utf-8'}); if (stampData) { const versionTag = fs.readFileSync(stampData, {encoding: 'utf-8'}) .split('\n') .find(s => s.startsWith('BUILD_SCM_VERSION')); // Don't assume BUILD_SCM_VERSION exists if (versionTag) { const version = versionTag.split(' ')[1].trim(); banner = banner.replace(/0.0.0-PLACEHOLDER/, version); } } } const config = { plugins, external: [TMPL_external], output: { globals: {TMPL_globals}, banner, } }; module.exports = config;