parent
bcaa07b0ac
commit
d9a0a8ff3e
|
@ -172,6 +172,7 @@ def _ng_package_impl(ctx):
|
|||
|
||||
packager_inputs = (
|
||||
ctx.files.srcs +
|
||||
ctx.files.data +
|
||||
esm5_sources.to_list() +
|
||||
depset(transitive = [d.typescript.transitive_declarations
|
||||
for d in ctx.attr.deps
|
||||
|
@ -186,6 +187,7 @@ def _ng_package_impl(ctx):
|
|||
packager_args.add(npm_package_directory.path)
|
||||
packager_args.add(ctx.label.package)
|
||||
packager_args.add([ctx.bin_dir.path, ctx.label.package], join_with="/")
|
||||
packager_args.add([ctx.genfiles_dir.path, ctx.label.package], join_with="/")
|
||||
|
||||
# Marshal the metadata into a JSON string so we can parse the data structure
|
||||
# in the TypeScript program easily.
|
||||
|
@ -213,6 +215,9 @@ def _ng_package_impl(ctx):
|
|||
packager_args.add(_flatten_paths(bundles), join_with=",")
|
||||
packager_args.add([s.path for s in ctx.files.srcs], join_with=",")
|
||||
|
||||
# TODO: figure out a better way to gather runfiles providers from the transitive closure.
|
||||
packager_args.add([d.path for d in ctx.files.data], join_with=",")
|
||||
|
||||
if ctx.file.license_banner:
|
||||
packager_inputs.append(ctx.file.license_banner)
|
||||
packager_args.add(ctx.file.license_banner.path)
|
||||
|
@ -246,6 +251,10 @@ NG_PACKAGE_ATTRS = dict(NPM_PACKAGE_ATTRS, **dict(ROLLUP_ATTRS, **{
|
|||
esm5_outputs_aspect,
|
||||
sources_aspect,
|
||||
]),
|
||||
"data": attr.label_list(
|
||||
doc = "Additional, non-Angular files to be added to the package, e.g. global CSS assets.",
|
||||
allow_files = True,
|
||||
),
|
||||
"include_devmode_srcs": attr.bool(default = False),
|
||||
"readme_md": attr.label(allow_single_file = FileType([".md"])),
|
||||
"globals": attr.string_dict(default={}),
|
||||
|
|
|
@ -14,6 +14,9 @@ function main(args: string[]): number {
|
|||
// Exit immediately when encountering an error.
|
||||
shx.set('-e');
|
||||
|
||||
// Keep track of whether an error has occured so that we can return an appropriate exit code.
|
||||
let errorHasOccured = false;
|
||||
|
||||
// This utility expects all of its arguments to be specified in a params file generated by
|
||||
// bazel (see https://docs.bazel.build/versions/master/skylark/lib/Args.html#use_param_file).
|
||||
const paramFilePath = args[0];
|
||||
|
@ -35,6 +38,9 @@ function main(args: string[]): number {
|
|||
// This is the intended output location for package artifacts.
|
||||
binDir,
|
||||
|
||||
// The bazel-genfiles dir joined with the srcDir (e.g. 'bazel-bin/package.common').
|
||||
genfilesDir,
|
||||
|
||||
// JSON data mapping each entry point to the generated bundle index and
|
||||
// flat module metadata, for example
|
||||
// {"@angular/core": {
|
||||
|
@ -67,6 +73,9 @@ function main(args: string[]): number {
|
|||
// List of all files in the ng_package rule's srcs.
|
||||
srcsArg,
|
||||
|
||||
// List of all files in the ng_package rule's data.
|
||||
dataArg,
|
||||
|
||||
// Path to the package's LICENSE.
|
||||
licenseFile,
|
||||
] = params;
|
||||
|
@ -77,6 +86,7 @@ function main(args: string[]): number {
|
|||
const esm5 = esm5Arg.split(',').filter(s => !!s);
|
||||
const bundles = bundlesArg.split(',').filter(s => !!s);
|
||||
const srcs = srcsArg.split(',').filter(s => !!s);
|
||||
const dataFiles: string[] = dataArg.split(',').filter(s => !!s);
|
||||
const modulesManifest = JSON.parse(modulesManifestArg);
|
||||
|
||||
if (readmeMd) {
|
||||
|
@ -84,31 +94,39 @@ function main(args: string[]): number {
|
|||
}
|
||||
|
||||
/**
|
||||
* Relativize the path where the file is written.
|
||||
* @param f a path relative to the srcDir, typically from a file in the srcs[]
|
||||
* @param c content of the file
|
||||
* Writes a file into the package based on its input path, relativizing to the package path.
|
||||
* @param inputPath Path to the file in the input tree.
|
||||
* @param fileContent Content of the file.
|
||||
*/
|
||||
function writeSrcFile(f: string, c: string) {
|
||||
mkDirWriteFile(path.join(out, path.relative(srcDir, f)), c);
|
||||
function writeFileFromInputPath(inputPath: string, fileContent: string) {
|
||||
// We want the relative path from the given file to its ancestor "root" directory.
|
||||
// This root depends on whether the file lives in the source tree (srcDir) as a basic file
|
||||
// input to ng_package, the bin output tree (binDir) as the output of another rule, or
|
||||
// the genfiles output tree (genfilesDir) as the output of a genrule.
|
||||
let rootDir: string;
|
||||
if (inputPath.includes(binDir)) {
|
||||
rootDir = binDir;
|
||||
} else if (inputPath.includes(genfilesDir)) {
|
||||
rootDir = genfilesDir;
|
||||
} else {
|
||||
rootDir = srcDir;
|
||||
}
|
||||
|
||||
const outputPath = path.join(out, path.relative(rootDir, inputPath));
|
||||
|
||||
// Always ensure that the target directory exists.
|
||||
shx.mkdir('-p', path.dirname(outputPath));
|
||||
fs.writeFileSync(outputPath, fileContent, 'utf-8');
|
||||
}
|
||||
|
||||
/**
|
||||
* Relativize the path where the file is written.
|
||||
* @param f a path relative to the binDir, typically from a file in the deps[]
|
||||
* @param c content of the file
|
||||
* Copies a file into the package based on its input path, relativizing to the package path.
|
||||
* @param inputPath a path relative to the binDir, typically from a file in the deps[]
|
||||
*/
|
||||
function writeBinFile(f: string, c: string) {
|
||||
const outputPath = path.join(out, path.relative(binDir, f));
|
||||
mkDirWriteFile(outputPath, c);
|
||||
return outputPath;
|
||||
function copyFileFromInputPath(inputPath: string) {
|
||||
writeFileFromInputPath(inputPath, fs.readFileSync(inputPath, 'utf-8'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the file, relativizing the path.
|
||||
* @param f a path relative to the binDir, typically from a file in the deps[]
|
||||
*/
|
||||
function copyBinFile(f: string) { writeBinFile(f, fs.readFileSync(f, 'utf-8')); }
|
||||
|
||||
/**
|
||||
* Relativize the path where a file is written.
|
||||
* @param file a path containing a re-rooted segment like .esm5 or .es6
|
||||
|
@ -135,9 +153,13 @@ function main(args: string[]): number {
|
|||
const content = fs.readFileSync(f, 'utf-8')
|
||||
// Strip the named AMD module for compatibility with non-bazel users
|
||||
.replace(/^\/\/\/ <amd-module name=.*\/>\n/, '');
|
||||
const outputPath = writeBinFile(f, content);
|
||||
writeFileFromInputPath(f, content);
|
||||
});
|
||||
|
||||
// Copy all `data` files into the package. These are files that aren't built by the ng_package
|
||||
// rule, but instead are just straight copied into the package, e.g. global CSS assets.
|
||||
dataFiles.forEach(f => copyFileFromInputPath(f));
|
||||
|
||||
// Iterate through the entry point modules
|
||||
// We do this first because we also record new paths for the esm5 and esm2015 copies
|
||||
// of the index JS file, which we need to amend the package.json.
|
||||
|
@ -149,11 +171,11 @@ function main(args: string[]): number {
|
|||
moduleFiles['esm5_index'] = path.join(binDir, 'esm5', relative);
|
||||
moduleFiles['esm2015_index'] = path.join(binDir, 'esm2015', relative);
|
||||
|
||||
writeBinFile(moduleFiles['esm5_index'], indexContent);
|
||||
writeBinFile(moduleFiles['esm2015_index'], indexContent);
|
||||
writeFileFromInputPath(moduleFiles['esm5_index'], indexContent);
|
||||
writeFileFromInputPath(moduleFiles['esm2015_index'], indexContent);
|
||||
|
||||
copyBinFile(moduleFiles['typings']);
|
||||
copyBinFile(moduleFiles['metadata']);
|
||||
copyFileFromInputPath(moduleFiles['typings']);
|
||||
copyFileFromInputPath(moduleFiles['metadata']);
|
||||
});
|
||||
|
||||
// Root package name (e.g. '@angular/common'), captures as we iterate through sources below.
|
||||
|
@ -161,6 +183,13 @@ function main(args: string[]): number {
|
|||
const packagesWithExistingPackageJson = new Set<string>();
|
||||
|
||||
for (const src of srcs) {
|
||||
if (src.includes(binDir) || src.includes(genfilesDir)) {
|
||||
errorHasOccured = true;
|
||||
console.error(
|
||||
'The "srcs" for ng_package should not include output of other rules. Found:\n' +
|
||||
` ${src}`);
|
||||
}
|
||||
|
||||
let content = fs.readFileSync(src, 'utf-8');
|
||||
// Modify package.json files as necessary for publishing
|
||||
if (path.basename(src) === 'package.json') {
|
||||
|
@ -177,7 +206,7 @@ function main(args: string[]): number {
|
|||
rootPackageName = packageJson['name'];
|
||||
}
|
||||
}
|
||||
writeSrcFile(src, content);
|
||||
writeFileFromInputPath(src, content);
|
||||
}
|
||||
|
||||
const licenseBanner = licenseFile ? fs.readFileSync(licenseFile, 'utf-8') : '';
|
||||
|
@ -196,7 +225,7 @@ function main(args: string[]): number {
|
|||
}
|
||||
});
|
||||
|
||||
return 0;
|
||||
return errorHasOccured ? 1 : 0;
|
||||
|
||||
/**
|
||||
* Convert a binDir-relative path to srcDir-relative
|
||||
|
@ -216,11 +245,6 @@ function main(args: string[]): number {
|
|||
!f.endsWith(`.ngsummary${ext}`);
|
||||
}
|
||||
|
||||
function mkDirWriteFile(p: string, content: string) {
|
||||
shx.mkdir('-p', path.dirname(p));
|
||||
fs.writeFileSync(p, content, 'utf-8');
|
||||
}
|
||||
|
||||
function copyFile(file: string, baseDir: string, relative = '.') {
|
||||
const dir = path.join(baseDir, relative);
|
||||
shx.mkdir('-p', dir);
|
||||
|
@ -240,6 +264,7 @@ function main(args: string[]): number {
|
|||
* Inserts or edits properties into the package.json file(s) in the package so that
|
||||
* they point to all the right generated artifacts.
|
||||
*
|
||||
* @param packageJson The path to the package.json file.
|
||||
* @param parsedPackage Parsed package.json content
|
||||
*/
|
||||
function amendPackageJson(packageJson: string, parsedPackage: {[key: string]: string}) {
|
||||
|
@ -298,13 +323,13 @@ function main(args: string[]): number {
|
|||
/** Creates metadata re-export file for a secondary entry-point. */
|
||||
function createMetadataReexportFile(entryPointName: string, metadataFile: string) {
|
||||
const inputPath = path.join(srcDir, `${entryPointName}.metadata.json`);
|
||||
writeSrcFile(inputPath, JSON.stringify({
|
||||
writeFileFromInputPath(inputPath, JSON.stringify({
|
||||
'__symbolic': 'module',
|
||||
'version': 3,
|
||||
'metadata': {},
|
||||
'exports':
|
||||
[{'from': `${srcDirRelative(inputPath, metadataFile.replace(/.metadata.json$/, ''))}`}],
|
||||
'flatModuleIndexRedirect': true
|
||||
'flatModuleIndexRedirect': true,
|
||||
}) + '\n');
|
||||
}
|
||||
|
||||
|
@ -317,18 +342,19 @@ function main(args: string[]): number {
|
|||
const content = `${license}
|
||||
export * from '${srcDirRelative(inputPath, typingsFile.replace(/\.d\.tsx?$/, ''))}';
|
||||
`;
|
||||
writeSrcFile(inputPath, content);
|
||||
writeFileFromInputPath(inputPath, content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a package.json for a secondary entry-point.
|
||||
* @param dir The directory under which the package.json should be written.
|
||||
* @param entryPointPackageName The full package name for the entry point,
|
||||
* e.g. '@angular/common/http'.
|
||||
*/
|
||||
function createEntryPointPackageJson(dir: string, entryPointPackageName: string) {
|
||||
const pkgJson = path.join(srcDir, dir, 'package.json');
|
||||
const content = amendPackageJson(pkgJson, {name: entryPointPackageName});
|
||||
writeSrcFile(pkgJson, content);
|
||||
writeFileFromInputPath(pkgJson, content);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,31 @@ ng_package(
|
|||
"package.json",
|
||||
"some-file.txt",
|
||||
],
|
||||
data = [
|
||||
":arbitrary_bin_file",
|
||||
":arbitrary_genfiles_file",
|
||||
":extra-styles.css",
|
||||
],
|
||||
entry_point = "packages/bazel/test/ng_package/example/index.js",
|
||||
deps = [
|
||||
":example",
|
||||
"//packages/bazel/test/ng_package/example/secondary",
|
||||
],
|
||||
)
|
||||
|
||||
# Use a genrule to create a file in bazel-genfiles to ensure that the genfiles output of
|
||||
# a rule can be passed through to the `data` of ng_package.
|
||||
genrule(
|
||||
name = "arbitrary_genfiles_file",
|
||||
outs = ["arbitrary_genfiles.txt"],
|
||||
cmd = "echo Hello > $@",
|
||||
)
|
||||
|
||||
# Use a genrule to create a file in bazel-bin to ensure that the bin output of
|
||||
# a rule can be passed through to the `data` of ng_package.
|
||||
genrule(
|
||||
name = "arbitrary_bin_file",
|
||||
outs = ["arbitrary_bin.txt"],
|
||||
cmd = "echo World > $@",
|
||||
output_to_bindir = True,
|
||||
)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
.special {
|
||||
color: goldenrod;
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
arbitrary_bin.txt
|
||||
arbitrary_genfiles.txt
|
||||
bundles
|
||||
bundles/example-secondary.umd.js
|
||||
bundles/example-secondary.umd.js.map
|
||||
|
@ -43,6 +45,7 @@ esm5
|
|||
esm5/secondary/secondarymodule.ngsummary.js
|
||||
example_public_index.d.ts
|
||||
example_public_index.metadata.json
|
||||
extra-styles.css
|
||||
fesm2015
|
||||
fesm2015/example.js
|
||||
fesm2015/example.js.map
|
||||
|
@ -65,6 +68,16 @@ secondary
|
|||
secondary.d.ts
|
||||
secondary.metadata.json
|
||||
some-file.txt
|
||||
--- arbitrary_bin.txt ---
|
||||
|
||||
World
|
||||
|
||||
|
||||
--- arbitrary_genfiles.txt ---
|
||||
|
||||
Hello
|
||||
|
||||
|
||||
--- bundles/example-secondary.umd.js ---
|
||||
|
||||
(function (global, factory) {
|
||||
|
@ -661,6 +674,13 @@ export * from './index';
|
|||
|
||||
{"__symbolic":"module","version":4,"metadata":{"MyModule":{"__symbolic":"class","decorators":[{"__symbolic":"call","expression":{"__symbolic":"reference","module":"@angular/core","name":"NgModule","line":11,"character":1},"arguments":[{}]}],"members":{}}},"origins":{"MyModule":"./mymodule"},"importAs":"example"}
|
||||
|
||||
--- extra-styles.css ---
|
||||
|
||||
.special {
|
||||
color: goldenrod;
|
||||
}
|
||||
|
||||
|
||||
--- fesm2015/example.js ---
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
|
|
Loading…
Reference in New Issue