From 280f2af55d001c73ee6ec5f259fe55b088360f2c Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 31 May 2017 18:21:52 +0200 Subject: [PATCH 1/3] 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) --- scripts/release/inline-resources.js | 138 ----------------------- tools/gulp/packaging/build-tasks-gulp.ts | 4 +- tools/gulp/packaging/inline-resources.ts | 58 ++++++++++ 3 files changed, 60 insertions(+), 140 deletions(-) delete mode 100644 scripts/release/inline-resources.js create mode 100644 tools/gulp/packaging/inline-resources.ts diff --git a/scripts/release/inline-resources.js b/scripts/release/inline-resources.js deleted file mode 100644 index 150556da4aff..000000000000 --- a/scripts/release/inline-resources.js +++ /dev/null @@ -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; diff --git a/tools/gulp/packaging/build-tasks-gulp.ts b/tools/gulp/packaging/build-tasks-gulp.ts index 1a85e74796f2..fe38c8ab8b4a 100644 --- a/tools/gulp/packaging/build-tasks-gulp.ts +++ b/tools/gulp/packaging/build-tasks-gulp.ts @@ -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 {inlineResourcesFolder} 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`, () => inlineResourcesFolder(packageOut)); /** * Watch tasks, that will rebuild the package whenever TS, SCSS, or HTML files change. diff --git a/tools/gulp/packaging/inline-resources.ts b/tools/gulp/packaging/inline-resources.ts new file mode 100644 index 000000000000..566f8d99bd18 --- /dev/null +++ b/tools/gulp/packaging/inline-resources.ts @@ -0,0 +1,58 @@ +/* tslint:disable:no-eval */ + +import {dirname, join} from 'path'; +import {readFileSync, writeFileSync} from 'fs'; +import {sync as glob} from 'glob'; + +/** Finds all JavaScript files and inlines all external resources of Angular components. */ +export function inlineResourcesFolder(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 templateFile = join(dirname(filePath), templateUrl); + const templateContent = loadResourceFile(templateFile); + 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, styleUrls) => { + // The RegExp matches the array of external style files. This is a string right now and + // can to be parsed using the `eval` method. + const parsedUrls = eval(styleUrls) as string[]; + + return 'styles: [' + parsedUrls.map(styleUrl => { + const stylePath = join(dirname(filePath), styleUrl); + const styleContent = loadResourceFile(stylePath); + return `"${styleContent}"`; + }).join(',\n') + ']'; + }); +} + +/** 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, '\\"'); +} From 3d7a8a3925be9023b850167742d28ec217d39d90 Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 31 May 2017 20:05:06 +0200 Subject: [PATCH 2/3] Address comments --- tools/gulp/packaging/build-tasks-gulp.ts | 4 ++-- tools/gulp/packaging/inline-resources.ts | 27 ++++++++++++------------ 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/tools/gulp/packaging/build-tasks-gulp.ts b/tools/gulp/packaging/build-tasks-gulp.ts index fe38c8ab8b4a..5ff8995599f9 100644 --- a/tools/gulp/packaging/build-tasks-gulp.ts +++ b/tools/gulp/packaging/build-tasks-gulp.ts @@ -5,7 +5,7 @@ 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 {inlineResourcesFolder} from './inline-resources'; +import {inlineResourcesForDirectory} from './inline-resources'; // There are no type definitions available for these imports. 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`, () => inlineResourcesFolder(packageOut)); + task(`${packageName}:assets:inline`, () => inlineResourcesForDirectory(packageOut)); /** * Watch tasks, that will rebuild the package whenever TS, SCSS, or HTML files change. diff --git a/tools/gulp/packaging/inline-resources.ts b/tools/gulp/packaging/inline-resources.ts index 566f8d99bd18..aa7718083ab3 100644 --- a/tools/gulp/packaging/inline-resources.ts +++ b/tools/gulp/packaging/inline-resources.ts @@ -4,8 +4,8 @@ import {dirname, join} from 'path'; import {readFileSync, writeFileSync} from 'fs'; import {sync as glob} from 'glob'; -/** Finds all JavaScript files and inlines all external resources of Angular components. */ -export function inlineResourcesFolder(folderPath: string) { +/** 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)); } @@ -23,25 +23,24 @@ export function inlineResources(filePath: string) { /** 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 templateFile = join(dirname(filePath), templateUrl); - const templateContent = loadResourceFile(templateFile); + 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, styleUrls) => { + 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. - const parsedUrls = eval(styleUrls) as string[]; - - return 'styles: [' + parsedUrls.map(styleUrl => { - const stylePath = join(dirname(filePath), styleUrl); - const styleContent = loadResourceFile(stylePath); - return `"${styleContent}"`; - }).join(',\n') + ']'; + // 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(',')}"]`; }); } From ef94b4bb40a9138549c653c96cb45374c5a54a9d Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Wed, 31 May 2017 20:41:12 +0200 Subject: [PATCH 3/3] Update comment --- tools/gulp/packaging/inline-resources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/gulp/packaging/inline-resources.ts b/tools/gulp/packaging/inline-resources.ts index aa7718083ab3..6d4002089eca 100644 --- a/tools/gulp/packaging/inline-resources.ts +++ b/tools/gulp/packaging/inline-resources.ts @@ -33,7 +33,7 @@ function inlineTemplate(fileContent: string, filePath: string) { 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"]" + // 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