mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
build: move inline resources script to tools (#4894)
* build: move inline resources script to tools * Moves the inline resources script to the `tools/gulp/packaging` folder. This is necessary when exposing the build tools (e.g for flex-layout) * This also makes the packaging more clean because no external script is referenced (also switched to TypeScript and improved code) * Address comments * Update comment
This commit is contained in:
committed by
mmalerba
parent
965bf18e49
commit
52b6692472
@@ -1,138 +0,0 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
|
||||
/**
|
||||
* Simple Promiseify function that takes a Node API and return a version that supports promises.
|
||||
* We use promises instead of synchronized functions to make the process less I/O bound and
|
||||
* faster. It also simplify the code.
|
||||
*/
|
||||
function promiseify(fn) {
|
||||
return function() {
|
||||
const args = [].slice.call(arguments, 0);
|
||||
return new Promise((resolve, reject) => {
|
||||
fn.apply(this, args.concat([function (err, value) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(value);
|
||||
}
|
||||
}]));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
const readFile = promiseify(fs.readFile);
|
||||
const writeFile = promiseify(fs.writeFile);
|
||||
|
||||
|
||||
function inlineResources(globs) {
|
||||
if (typeof globs == 'string') {
|
||||
globs = [globs];
|
||||
}
|
||||
|
||||
/**
|
||||
* For every argument, inline the templates and styles under it and write the new file.
|
||||
*/
|
||||
return Promise.all(globs.map(pattern => {
|
||||
if (pattern.indexOf('*') < 0) {
|
||||
// Argument is a directory target, add glob patterns to include every files.
|
||||
pattern = path.join(pattern, '**', '*');
|
||||
}
|
||||
|
||||
const files = glob.sync(pattern, {})
|
||||
.filter(name => /\.js$/.test(name)); // Matches only JavaScript files.
|
||||
|
||||
// Generate all files content with inlined templates.
|
||||
return Promise.all(files.map(filePath => {
|
||||
return readFile(filePath, 'utf-8')
|
||||
.then(content => inlineResourcesFromString(content, url => {
|
||||
return path.join(path.dirname(filePath), url);
|
||||
}))
|
||||
.then(content => writeFile(filePath, content))
|
||||
.catch(err => {
|
||||
console.error('An error occurred: ', err);
|
||||
});
|
||||
}));
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline resources from a string content.
|
||||
* @param content {string} The source file's content.
|
||||
* @param urlResolver {Function} A resolver that takes a URL and return a path.
|
||||
* @returns {string} The content with resources inlined.
|
||||
*/
|
||||
function inlineResourcesFromString(content, urlResolver) {
|
||||
// Curry through the inlining functions.
|
||||
return [
|
||||
inlineTemplate,
|
||||
inlineStyle,
|
||||
removeModuleId
|
||||
].reduce((content, fn) => fn(content, urlResolver), content);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
inlineResources(process.argv.slice(2));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inline the templates for a source file. Simply search for instances of `templateUrl: ...` and
|
||||
* replace with `template: ...` (with the content of the file included).
|
||||
* @param content {string} The source file's content.
|
||||
* @param urlResolver {Function} A resolver that takes a URL and return a path.
|
||||
* @return {string} The content with all templates inlined.
|
||||
*/
|
||||
function inlineTemplate(content, urlResolver) {
|
||||
return content.replace(/templateUrl:\s*'([^']+?\.html)'/g, function(m, templateUrl) {
|
||||
const templateFile = urlResolver(templateUrl);
|
||||
const templateContent = fs.readFileSync(templateFile, 'utf-8');
|
||||
const shortenedTemplate = templateContent
|
||||
.replace(/([\n\r]\s*)+/gm, ' ')
|
||||
.replace(/"/g, '\\"');
|
||||
return `template: "${shortenedTemplate}"`;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inline the styles for a source file. Simply search for instances of `styleUrls: [...]` and
|
||||
* replace with `styles: [...]` (with the content of the file included).
|
||||
* @param urlResolver {Function} A resolver that takes a URL and return a path.
|
||||
* @param content {string} The source file's content.
|
||||
* @return {string} The content with all styles inlined.
|
||||
*/
|
||||
function inlineStyle(content, urlResolver) {
|
||||
return content.replace(/styleUrls:\s*(\[[\s\S]*?\])/gm, function(m, styleUrls) {
|
||||
const urls = eval(styleUrls);
|
||||
return 'styles: ['
|
||||
+ urls.map(styleUrl => {
|
||||
const styleFile = urlResolver(styleUrl);
|
||||
const styleContent = fs.readFileSync(styleFile, 'utf-8');
|
||||
const shortenedStyle = styleContent
|
||||
.replace(/([\n\r]\s*)+/gm, ' ')
|
||||
.replace(/"/g, '\\"');
|
||||
return `"${shortenedStyle}"`;
|
||||
})
|
||||
.join(',\n')
|
||||
+ ']';
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove every mention of `moduleId: module.id`.
|
||||
* @param content {string} The source file's content.
|
||||
* @returns {string} The content with all moduleId: mentions removed.
|
||||
*/
|
||||
function removeModuleId(content) {
|
||||
return content.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
|
||||
}
|
||||
|
||||
|
||||
module.exports = inlineResources;
|
||||
module.exports.inlineResourcesFromString = inlineResourcesFromString;
|
||||
@@ -5,9 +5,9 @@ import {SOURCE_ROOT, DIST_ROOT, HTML_MINIFIER_OPTIONS} from '../build-config';
|
||||
import {sequenceTask, sassBuildTask, copyTask, triggerLivereload} from '../util/task_helpers';
|
||||
import {composeRelease} from './build-release';
|
||||
import {buildPackageBundles} from './build-bundles';
|
||||
import {inlineResourcesForDirectory} from './inline-resources';
|
||||
|
||||
// There are no type definitions available for these imports.
|
||||
const inlineResources = require('../../../scripts/release/inline-resources');
|
||||
const htmlmin = require('gulp-htmlmin');
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ export function createPackageBuildTasks(packageName: string, requiredPackages: s
|
||||
return src(htmlGlob).pipe(htmlmin(HTML_MINIFIER_OPTIONS)).pipe(dest(packageOut));
|
||||
});
|
||||
|
||||
task(`${packageName}:assets:inline`, () => inlineResources(packageOut));
|
||||
task(`${packageName}:assets:inline`, () => inlineResourcesForDirectory(packageOut));
|
||||
|
||||
/**
|
||||
* Watch tasks, that will rebuild the package whenever TS, SCSS, or HTML files change.
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/* tslint:disable:no-eval */
|
||||
|
||||
import {dirname, join} from 'path';
|
||||
import {readFileSync, writeFileSync} from 'fs';
|
||||
import {sync as glob} from 'glob';
|
||||
|
||||
/** Finds all JavaScript files in a directory and inlines all resources of Angular components. */
|
||||
export function inlineResourcesForDirectory(folderPath: string) {
|
||||
glob(join(folderPath, '**/*.js')).forEach(filePath => inlineResources(filePath));
|
||||
}
|
||||
|
||||
/** Inlines the external resources of Angular components of a file. */
|
||||
export function inlineResources(filePath: string) {
|
||||
let fileContent = readFileSync(filePath, 'utf-8');
|
||||
|
||||
fileContent = inlineTemplate(fileContent, filePath);
|
||||
fileContent = inlineStyles(fileContent, filePath);
|
||||
fileContent = removeModuleId(fileContent);
|
||||
|
||||
writeFileSync(filePath, fileContent, 'utf-8');
|
||||
}
|
||||
|
||||
/** Inlines the templates of Angular components for a specified source file. */
|
||||
function inlineTemplate(fileContent: string, filePath: string) {
|
||||
return fileContent.replace(/templateUrl:\s*'([^']+?\.html)'/g, (match, templateUrl) => {
|
||||
const templatePath = join(dirname(filePath), templateUrl);
|
||||
const templateContent = loadResourceFile(templatePath);
|
||||
return `template: "${templateContent}"`;
|
||||
});
|
||||
}
|
||||
|
||||
/** Inlines the external styles of Angular components for a specified source file. */
|
||||
function inlineStyles(fileContent: string, filePath: string) {
|
||||
return fileContent.replace(/styleUrls:\s*(\[[\s\S]*?])/gm, (match, styleUrlsValue) => {
|
||||
// The RegExp matches the array of external style files. This is a string right now and
|
||||
// can to be parsed using the `eval` method. The value looks like "['AAA.css', 'BBB.css']"
|
||||
const styleUrls = eval(styleUrlsValue) as string[];
|
||||
|
||||
const styleContents = styleUrls
|
||||
.map(url => join(dirname(filePath), url))
|
||||
.map(path => loadResourceFile(path));
|
||||
|
||||
return `styles: ["${styleContents.join(',')}"]`;
|
||||
});
|
||||
}
|
||||
|
||||
/** Remove every mention of `moduleId: module.id` */
|
||||
function removeModuleId(fileContent: string) {
|
||||
return fileContent.replace(/\s*moduleId:\s*module\.id\s*,?\s*/gm, '');
|
||||
}
|
||||
|
||||
/** Loads the specified resource file and drops line-breaks of the content. */
|
||||
function loadResourceFile(filePath: string): string {
|
||||
return readFileSync(filePath, 'utf-8')
|
||||
.replace(/([\n\r]\s*)+/gm, ' ')
|
||||
.replace(/"/g, '\\"');
|
||||
}
|
||||
Reference in New Issue
Block a user