build: zipper revival (#3319)

This commit is contained in:
Jesús Rodríguez 2017-02-28 23:31:24 +01:00 committed by GitHub
parent 0f8b1dfa7a
commit e8a062bdd2
14 changed files with 222 additions and 130 deletions

View File

@ -46,7 +46,7 @@ var LIVE_EXAMPLES_PATH = path.join(RESOURCES_PATH, 'live-examples');
var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less');
var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder'));
var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper'));
var ExampleZipper = require(path.resolve(TOOLS_PATH, 'example-zipper/exampleZipper'));
var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPlunker'));
var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker'));
var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils'));
@ -572,9 +572,7 @@ gulp.task('build-and-serve', ['build-docs'], function (cb) {
watchAndSync({localFiles: true}, cb);
});
gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers']);
// Stop zipping examples Feb 28, 2016
//gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']);
gulp.task('build-docs', ['build-devguide-docs', 'build-api-docs', 'build-plunkers', '_zip-examples']);
gulp.task('build-api-docs', ['build-js-api-docs', 'build-ts-api-docs']);
@ -787,8 +785,8 @@ gulp.task('_shred-clean-api', function(cb) {
});
gulp.task('_zip-examples', function() {
exampleZipper.zipExamples(_devguideShredOptions.examplesDir, _devguideShredOptions.zipDir);
exampleZipper.zipExamples(_apiShredOptions.examplesDir, _apiShredOptions.zipDir);
new ExampleZipper(_devguideShredOptions.examplesDir, _devguideShredOptions.zipDir);
// exampleZipper.zipExamples(_apiShredOptions.examplesDir, _apiShredOptions.zipDir);
});

View File

@ -0,0 +1,10 @@
{
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0-9].*",
".angular-cli.json",
"protractor.conf.js"
],
"removeSystemJsConfig": true
}

View File

@ -4,9 +4,31 @@
"private": true,
"description": "Master package.json, the superset of all dependencies for all of the _example package.json files. See _boilerplate/package.json for example npm scripts.",
"scripts": {
"http-server": "http-server",
"protractor": "protractor",
"webdriver:update": "webdriver-manager update --standalone false --gecko false"
"build": "tsc -p src/",
"build:watch": "tsc -p src/ -w",
"build:e2e": "tsc -p e2e/",
"serve": "lite-server -c=bs-config.json",
"prestart": "npm run build",
"start": "concurrently \"npm run build:watch\" \"npm run serve\"",
"protractor": "protractor protractor.config.js",
"pretest": "npm run build",
"test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
"pretest:once": "npm run build",
"test:once": "karma start karma.conf.js --single-run",
"lint": "tslint ./src/**/*.ts -t verbose",
"build:upgrade": "tsc",
"serve:upgrade": "http-server",
"build:cli": "ng build --no-progress",
"serve:cli": "http-server dist/",
"build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup-config.js",
"serve:aot": "lite-server -c bs-config.aot.json",
"start:webpack": "webpack-dev-server --inline --progress --port 8080",
"test:webpack": "karma start karma.webpack.conf.js",
"build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail",
"build:babel": "babel src -d src --extensions \".es6\" --source-maps",
"copy-dist-files": "node ./copy-dist-files.js",
"i18n": "ng-xi18n"
},
"keywords": [],
"author": "",

View File

@ -0,0 +1,11 @@
{
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0-9].*",
"config/**/*",
"webpack.config.js",
"karma.webpack.conf.js"
],
"removeSystemJsConfig": true
}

View File

@ -23,6 +23,7 @@ include _util-fns
3. [Serve](#serve) the application
4. [Edit](#first-component) the application
And you can also <a href="/resources/zips/cli-quickstart/cli-quickstart.zip">download the example.</a>
.l-main-section
h2#devenv Step 1. Set up the Development Environment

View File

@ -5,6 +5,10 @@ block includes
The Angular documentation is a living document with continuous improvements.
This log calls attention to recent significant changes.
## NEW: Downloadable examples for each guide (2017-02-28)
Now you can download the sample code for any guide and run it locally.
Look for the new download links next to the "live example" links.
## Template Syntax/Structural Directives: refreshed (2017-02-06)
The [_Template-Syntax_](template-syntax.html) and [_Structural Directives_](structural-directives.html)
guides were significantly revised for clarity, accuracy, and current recommended practices.

View File

@ -72,11 +72,14 @@ table(width="100%")
You can reuse these snippets in your applications.
Look for a link to a running version of that sample, often near the top of the page,
such as this <live-example name="architecture"></live-example> from the [Architecture](architecture.html) page.
such as this <live-example nodownload name="architecture"></live-example> from the [Architecture](architecture.html) page.
<span if-docs="ts">
The link launches a browser-based, code editor where you can inspect, modify, save, and download the code.
</span>
Alternatively, you can run the example locally, next to those `live-example` links you have a <a href="/resources/zips/architecture/architecture.zip">download link</a>.
Just download, unzip, run `npm install` to install the dependencies and run it with `npm start`.
## Reference pages
* The [Cheat Sheet](cheatsheet.html) lists Angular syntax for common scenarios.

View File

@ -32,7 +32,9 @@ style.
[Trying it out](#try)
[Conclusions](#conclusions)
You can also <a href="/resources/zips/webpack/webpack.zip">download the final result.</a>
.l-main-section
<a id="what-is-webpack"></a>
:marked

View File

@ -10,7 +10,7 @@ block includes
block qs-src-online-and-local
.l-sub-section
:marked
Try this **<live-example>QuickStart example on Plunker</live-example>** without installing anything.
Try this **<live-example noDownload>QuickStart example on Plunker</live-example>** without installing anything.
Try it locally with the [***QuickStart seed***](guide/setup.html "Setup for local development with the QuickStart seed")
and prepare for development of a real Angular application.

View File

@ -56,11 +56,12 @@ angularIO.directive('liveExample', ['$location', function ($location) {
function span(text) { return '<span>' + text + '</span>'; }
function embeddedTemplate(src, img) {
function embeddedTemplate(src, img, zipHref) {
return '<div ng-if="embeddedShow">' +
'<iframe frameborder="0" width="100%" height="100%" src="' + src + '"></iframe>' +
'</div>' +
'<img ng-click="toggleEmbedded()" ng-if="!embeddedShow" src="' + img + '" alt="plunker">';
'<img ng-click="toggleEmbedded()" ng-if="!embeddedShow" src="' + img + '" alt="plunker">' +
'<p>You can also <a href="' + zipHref +'">download this example.</p>';
}
return {
@ -72,24 +73,29 @@ angularIO.directive('liveExample', ['$location', function ($location) {
if (attrs['title'] == undefined) { tElement[0].setAttribute('title', text); } // set default title (tooltip)
var ex = attrs.name || NgIoUtil.getExampleName($location);
var embedded = attrs.hasOwnProperty('embedded');
var noDownload = attrs.hasOwnProperty('nodownload') || attrs.hasOwnProperty('noDownload');
var flatStyle = attrs.hasOwnProperty('flatstyle') || attrs.hasOwnProperty('flatStyle');
var embeddedStyle = embedded || attrs.hasOwnProperty('embeddedstyle') || attrs.hasOwnProperty('embeddedStyle');
var plnkr = (embeddedStyle || !flatStyle) ? 'eplnkr' : 'plnkr';
var zipHref = ex;
var imageBase = '/resources/images/';
var defaultImg = 'plunker/placeholder.png';
if (attrs.plnkr) {
plnkr = attrs.plnkr + '.' + plnkr;
zipHref = attrs.plnkr + '.' + zipHref;
}
var isForDart = attrs.lang === 'dart' || NgIoUtil.isDoc($location, 'dart');
var isForJs = attrs.lang === 'js' || NgIoUtil.isDoc($location, 'js');
var exLang = isForDart ? 'dart' : isForJs ? 'js' : 'ts';
zipHref = '/resources/zips/' + ex + '/' + zipHref + '.zip';
if (embedded && !isForDart) {
href = '/resources/live-examples/' + ex + '/' + exLang + '/' + plnkr + '.html';
img = imageBase + (attrs.img || defaultImg);
template = embeddedTemplate(href, img);
template = embeddedTemplate(href, img, zipHref);
} else {
var href = isForDart
? 'http://angular-examples.github.io/' + ex
@ -98,6 +104,10 @@ angularIO.directive('liveExample', ['$location', function ($location) {
// Link to live example.
var template = a(text, { href: href, target: '_blank' });
if (!noDownload) {
template += ' / ' + a('downloadable example', { href: zipHref, target: '_blank' });
}
// The hosted example and sources are in different locations for Dart.
// Also show link to sources for Dart, unless noSource is specified.
if (isForDart && !attrs.hasOwnProperty('nosource')) {

View File

@ -1,15 +0,0 @@
Summary:
1) if we discover a 'zipconfig.json' file or an 'xxx.zipconfig.json' file with the following structure
{
"zipRegion": "zip",
"files": [ "foo.js", "**/**/.css", "!xxx.css"]
}
where "zipRegion" is optional.
Then we zip up all of the files specified, cleaning and removing extra doc tags. If the specified 'zipRegion'
is discovered in any file then we only zip that region. Otherwise we zip the entire file.

View File

@ -1,100 +0,0 @@
// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes
var path = require('canonical-path');
var jsonfile = require('jsonfile');
var assert = require('assert-plus');
// adm-zip does not work properly on Windows
// var Zip = require('adm-zip');
var archiver = require('archiver');
var fs = require('fs');
var mkdirp = require('mkdirp');
var globby = require('globby');
var regionExtractor = require('../doc-shredder/regionExtractor');
// globs is an array of globs
function zipExamples(sourceDirName, outputDirName) {
var gpath = path.join(sourceDirName, '**/*zipconfig.json');
var configFileNames = globby.sync([gpath], { ignore: ['**/node_modules/**'] });
configFileNames.forEach(function(configFileName) {
zipExample(configFileName, sourceDirName, outputDirName);
});
}
function zipExample(configFileName, sourceDirName, outputDirName) {
var json = jsonfile.readFileSync(configFileName);
var fileGlobs = json.files;
var zipRegionName = json.zipRegion;
// assert that fileGlobs is an array
assert.arrayOfString(fileGlobs, 'files property should be an array of strings');
// backup two from the relative configFileName
var relativeDirName = path.dirname(path.dirname(path.relative(sourceDirName, configFileName)));
var configDirName = path.dirname(configFileName);
// use the dir name of the folder containing the config file as the base file name of the zip file
var baseFileName = path.basename(configDirName);
// check if there is a prefix name before zipconfig.json
if (configFileName.indexOf('.zipconfig.json') >= 0) {
// if so use it as a suffix to the baseFileName
var extraName = path.basename(configFileName, '.zipconfig.json');
baseFileName = baseFileName + "." + extraName;
}
var outputFileName = path.join(outputDirName, relativeDirName, baseFileName + ".zip");
// old code
// var fileNames = globule.find(fileGlobs, { srcBase: configDirName, prefixBase: configDirName });
fileGlobs = fileGlobs.map(function(fileGlob) {
return path.join(configDirName, fileGlob);
});
var fileNames = globby.sync(fileGlobs, { ignore: ["**/node_modules/**"] });
var zip = createZipArchive(outputFileName);
fileNames.forEach(function(fileName) {
var relativePath = path.relative(configDirName, fileName);
var content = fs.readFileSync(fileName, 'utf8');
var extn = path.extname(fileName).substr(1);
// if we don't need to clean up the file then we can do the following.
// zip.append(fs.createReadStream(fileName), { name: relativePath });
var output;
// if no zipRegion or zipRegion is not in content then just clean the content
if (zipRegionName != null) {
output = regionExtractor.getRegionDoc(content, extn, zipRegionName);
}
if (!output) {
output = regionExtractor.removeDocTags(content, extn);
}
zip.append(output, { name: relativePath } )
});
zip.finalize();
}
function createZipArchive(zipFileName) {
var dirName = path.dirname(zipFileName);
// insure that the folder exists.
if (!fs.existsSync(dirName)) {
mkdirp.sync(dirName);
}
var output = fs.createWriteStream(zipFileName);
var archive = archiver('zip');
output.on('close', function () {
console.log('zip created: ' + zipFileName + ' (' + archive.pointer() + ' total bytes)');
});
archive.on('error', function (err) {
throw err;
});
archive.pipe(output);
return archive;
}
module.exports = {
zipExamples: zipExamples,
zipExample: zipExample
};

View File

@ -0,0 +1,146 @@
// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes
var path = require('canonical-path');
var jsonfile = require('jsonfile');
var assert = require('assert-plus');
// adm-zip does not work properly on Windows
// var Zip = require('adm-zip');
var archiver = require('archiver');
var fs = require('fs');
var mkdirp = require('mkdirp');
var globby = require('globby');
var regionExtractor = require('../doc-shredder/regionExtractor');
class ExampleZipper {
constructor(sourceDirName, outputDirName) {
let gpathPlnkr = path.join(sourceDirName, '**/*plnkr.json');
let gpathZipper = path.join(sourceDirName, '**/zipper.json');
let configFileNames = globby.sync([gpathPlnkr, gpathZipper], { ignore: ['**/node_modules/**'] });
// we only need typescript examples
configFileNames = configFileNames.filter((configFileName) => {
return configFileName.indexOf('ts') != -1;
});
configFileNames.forEach((configFileName) => {
this._zipExample(configFileName, sourceDirName, outputDirName);
});
}
_changeTypeRoots(tsconfig) {
return tsconfig.replace('../../../', '../');
}
_createZipArchive(zipFileName) {
let dirName = path.dirname(zipFileName);
// ensure that the folder exists.
if (!fs.existsSync(dirName)) {
mkdirp.sync(dirName);
}
let output = fs.createWriteStream(zipFileName);
let archive = archiver('zip');
output.on('close', function () {
console.log('zip created: ' + zipFileName + ' (' + archive.pointer() + ' total bytes)');
});
archive.on('error', function (err) {
throw err;
});
archive.pipe(output);
return archive;
}
_zipExample(configFileName, sourceDirName, outputDirName) {
let json = JSON.parse(fs.readFileSync(configFileName, 'utf-8'));
const basePath = json.basePath || '';
const jsonFileName = configFileName.replace(/^.*[\\\/]/, '');
const relativeDirName = path.dirname(path.dirname(path.relative(sourceDirName, configFileName)));
const exampleDirName = path.dirname(configFileName);
const examplesPackageJson = 'public/docs/_examples/package.json';
const examplesSystemjsConfig = 'public/docs/_examples/_boilerplate/src/systemjs.config.js';
const exampleTsconfig = 'public/docs/_examples/_boilerplate/src/tsconfig.json';
let exampleZipName = jsonFileName.replace(/(plnkr|zipper).json/, relativeDirName);
const outputFileName = path.join(outputDirName, relativeDirName, exampleZipName + '.zip');
let defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png'];
let alwaysIncludes = ['bs-config.json', 'tslint.json', 'karma-test-shim.js', 'karma.conf.js', 'src/testing/**/*'];
var defaultExcludes = [
'!**/bs-config.e2e.json',
'!**/*plnkr.*',
'!**/*zipper.*',
'!**/systemjs.config.js',
'!**/npm-debug.log',
'!**/package.json',
'!**/example-config.json',
'!**/wallaby.js',
'!**/tsconfig.json',
'!**/package.webpack.json',
// AoT related files
'!**/aot/**/*.*',
'!**/*-aot.*'
];
if (json.files) {
if (json.files.length > 0) {
json.files = json.files.map(file => {
if (file.startsWith('!')) {
if (file.startsWith('!**')) {
return file;
}
return '!' + basePath + file.substr(1);
}
return basePath + file;
});
if (json.files[0].substr(0, 1) === '!') {
json.files = defaultIncludes.concat(json.files);
}
}
} else {
json.files = defaultIncludes;
}
json.files = json.files.concat(alwaysIncludes);
let gpaths = json.files.map((fileName) => {
fileName = fileName.trim();
if (fileName.substr(0, 1) === '!') {
return '!' + path.join(exampleDirName, fileName.substr(1));
} else {
return path.join(exampleDirName, fileName);
}
});
Array.prototype.push.apply(gpaths, defaultExcludes);
let fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**']});
let zip = this._createZipArchive(outputFileName);
fileNames.forEach((fileName) => {
let relativePath = path.relative(exampleDirName, fileName);
let content = fs.readFileSync(fileName, 'utf8');
let extn = path.extname(fileName).substr(1);
// if we don't need to clean up the file then we can do the following.
// zip.append(fs.createReadStream(fileName), { name: relativePath });
let output = regionExtractor.removeDocTags(content, extn);
zip.append(output, { name: relativePath } )
});
// we need the package.json from _examples root, not the _boilerplate one
zip.append(fs.readFileSync(examplesPackageJson, 'utf8'), { name: 'package.json' });
// also a systemjs config
if (!json.removeSystemJsConfig) {
zip.append(fs.readFileSync(examplesSystemjsConfig, 'utf8'), { name: 'src/systemjs.config.js' });
}
// a modified tsconfig
let tsconfig = fs.readFileSync(exampleTsconfig, 'utf8');
zip.append(this._changeTypeRoots(tsconfig), {name: 'src/tsconfig.json'});
zip.finalize();
}
}
module.exports = ExampleZipper;