|
1 | 1 | import {spawn} from 'child_process';
|
2 |
| -import {existsSync, statSync, copySync, writeFileSync} from 'fs-extra'; |
3 |
| -import {join} from 'path'; |
| 2 | +import {existsSync, statSync, copySync, writeFileSync, readFileSync} from 'fs-extra'; |
| 3 | +import {join, basename} from 'path'; |
4 | 4 | import {task, src, dest} from 'gulp';
|
5 | 5 | import {execTask, sequenceTask} from '../util/task_helpers';
|
6 | 6 | import {
|
7 |
| - DIST_RELEASE, DIST_BUNDLES, DIST_MATERIAL, COMPONENTS_DIR, LICENSE_BANNER |
| 7 | + DIST_RELEASE, DIST_BUNDLES, DIST_MATERIAL, COMPONENTS_DIR, LICENSE_BANNER, DIST_ROOT |
8 | 8 | } from '../constants';
|
9 | 9 | import * as minimist from 'minimist';
|
10 | 10 |
|
11 | 11 | // There are no type definitions available for these imports.
|
12 |
| -const gulpRename = require('gulp-rename'); |
| 12 | +const glob = require('glob'); |
13 | 13 |
|
14 | 14 | /** Parse command-line arguments for release task. */
|
15 | 15 | const argv = minimist(process.argv.slice(3));
|
@@ -38,21 +38,33 @@ task(':package:release', [
|
38 | 38 | ]);
|
39 | 39 |
|
40 | 40 | /** Copy metatadata.json and associated d.ts files to the root of the package structure. */
|
41 |
| -task(':package:metadata', [':package:fix-metadata'], () => { |
| 41 | +task(':package:metadata', [':inline-metadata-resources'], () => { |
42 | 42 | // See: https://github.com/angular/angular/blob/master/build.sh#L293-L294
|
43 | 43 | copySync(join(DIST_MATERIAL, 'index.metadata.json'),
|
44 | 44 | join(DIST_RELEASE, 'material.metadata.json'));
|
45 | 45 | });
|
46 | 46 |
|
47 |
| -/** |
48 |
| - * Workaround for a @angular/tsc-wrapped issue, where the compiler looks for component assets |
49 |
| - * in the wrong folder. This issue only appears for bundled metadata files. |
50 |
| - * As a workaround, we just copy all assets next to the metadata bundle. |
51 |
| - **/ |
52 |
| -task(':package:fix-metadata', () => { |
53 |
| - return src('**/*.+(html|css)', { cwd: DIST_MATERIAL }) |
54 |
| - .pipe(gulpRename({dirname: ''})) |
55 |
| - .pipe(dest(DIST_RELEASE)); |
| 47 | +/** Inlines the html and css resources into all metadata.json files in dist/ */ |
| 48 | +task(':inline-metadata-resources', () => { |
| 49 | + // Create a map of fileName -> fullFilePath. This is needed because the templateUrl and |
| 50 | + // styleUrls for each component use just the filename because, in the source, the component |
| 51 | + // and the resources live in the same directory. |
| 52 | + const componentResources = new Map<string, string>(); |
| 53 | + glob(join(DIST_MATERIAL, '**/*.+(html|css)'), (err: any, resourceFilePaths: any) => { |
| 54 | + for (const path of resourceFilePaths) { |
| 55 | + componentResources.set(basename(path), path); |
| 56 | + } |
| 57 | + }); |
| 58 | + |
| 59 | + // Find all metadata files. For each one, parse the JSON content, inline the resources, and |
| 60 | + // reserialize and rewrite back to the original location. |
| 61 | + glob(join(DIST_ROOT, '**/*.metadata.json'), (err: any, metadataFilePaths: any) => { |
| 62 | + for (const path of metadataFilePaths) { |
| 63 | + let metadata = JSON.parse(readFileSync(path, 'utf-8')); |
| 64 | + inlineMetadataResources(metadata, componentResources); |
| 65 | + writeFileSync(path , JSON.stringify(metadata), 'utf-8'); |
| 66 | + } |
| 67 | + }) |
56 | 68 | });
|
57 | 69 |
|
58 | 70 | task(':package:assets', () => src(assetsGlob).pipe(dest(DIST_RELEASE)));
|
@@ -155,3 +167,36 @@ task('publish', sequenceTask(
|
155 | 167 | ':publish',
|
156 | 168 | ':publish:logout',
|
157 | 169 | ));
|
| 170 | + |
| 171 | + |
| 172 | +/** |
| 173 | + * Recurse through a parsed metadata.json file and inline all html and css. |
| 174 | + * Note: this assumes that all html and css files have a unique name. |
| 175 | + */ |
| 176 | +function inlineMetadataResources(metadata: any, componentResources: Map<string, string>) { |
| 177 | + // Convert `templateUrl` to `template` |
| 178 | + if (metadata.templateUrl) { |
| 179 | + const fullResourcePath = componentResources.get(metadata.templateUrl); |
| 180 | + metadata.template = readFileSync(fullResourcePath, 'utf-8'); |
| 181 | + delete metadata.templateUrl; |
| 182 | + } |
| 183 | + |
| 184 | + // Convert `styleUrls` to `styles` |
| 185 | + if (metadata.styleUrls && metadata.styleUrls.length) { |
| 186 | + metadata.styles = []; |
| 187 | + for (const styleUrl of metadata.styleUrls) { |
| 188 | + const fullResourcePath = componentResources.get(styleUrl); |
| 189 | + metadata.styles.push(readFileSync(fullResourcePath, 'utf-8')); |
| 190 | + } |
| 191 | + delete metadata.styleUrls; |
| 192 | + } |
| 193 | + |
| 194 | + // We we did nothing at this node, go deeper. |
| 195 | + if (!metadata.template && !metadata.styles) { |
| 196 | + for (const property in metadata) { |
| 197 | + if (typeof metadata[property] == 'object' && metadata[property]) { |
| 198 | + inlineMetadataResources(metadata[property], componentResources); |
| 199 | + } |
| 200 | + } |
| 201 | + } |
| 202 | +} |
0 commit comments