|
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