Skip to content

Commit

Permalink
refactor(build): refactor to support AoT
Browse files Browse the repository at this point in the history
BREAKING CHANGE:
NPM Package now comes with ES6 Module version (ESM) and an ES5 UMD bundle (1 file), this should'nt have any effect. (CJS version removed)
ES6 version contains `d.ts` files as well as `metadata.json` files for AoT Compilation.

This breaking change mainly effect the development process of angular2-modal.
To support AoT a complete restructiing of the NPM package and build process was needed. Some devDependencies removed and some changed.
Development process is now managed by Webpack 2.
It is recommended to delete the node_modules directory and `npm install` again.

closes #206
closes #207
closes #204
  • Loading branch information
Shlomi Assaf (shlassaf) committed Oct 2, 2016
1 parent bf54101 commit 9db8f5e
Show file tree
Hide file tree
Showing 25 changed files with 128 additions and 7,342 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tmp
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
/build
/dist
.idea
/compiled
*.ngfactory.ts

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Update
Version 1.1.2 & 2.0.0-beta.3 now support UMD bundles.

Version 2.0.0-beta.14 now supports AoT compilation.

# Angular 2: AIO Modal / Dialog window

Expand Down
11 changes: 1 addition & 10 deletions config/webpack.common.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ module.exports = {
helpers.root('src/components')
],
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js', '.json', '.css', '.html'],
modules: [helpers.root('src'), 'node_modules'],
modulesDirectories: ['node_modules']
},

Expand Down Expand Up @@ -162,16 +163,6 @@ module.exports = {
*/
new ForkCheckerPlugin(),

/*
* Plugin: OccurenceOrderPlugin
* Description: Varies the distribution of the ids to get the smallest id length
* for often used ids.
*
* See: https://webpack.github.io/docs/list-of-plugins.html#occurrenceorderplugin
* See: https://github.com/webpack/docs/wiki/optimization#minimize
*/
new webpack.optimize.OccurenceOrderPlugin(true),

/*
* Plugin: CommonsChunkPlugin
* Description: Shares common code between the pages.
Expand Down
4 changes: 2 additions & 2 deletions gulp/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function prepareCommands(pluginName) {
const rollupRoot = pluginName ? path.join(config.PATHS.pluginDir, pluginName) : '';

return {
ts: `./node_modules/.bin/ngc -p tsconfig.json --out ${path.join(config.PATHS.dist.bundles, filename)} --target es5 --allowJs ${path.join(config.PATHS.tmp, filename)}`,
ts: `./node_modules/.bin/tsc --out ${path.join(config.PATHS.dist.bundles, filename)} --target es5 --allowJs ${path.join(config.PATHS.tmp, filename)}`,
rollup: `./node_modules/.bin/rollup -c ${path.join(rollupRoot, ROLLUP_CONFIG)}`
}
}
Expand All @@ -42,7 +42,7 @@ function getShellCommands() {

const commands = getShellCommands();

gulp.task('rollup:umd', ['scripts:esm'], $.shell.task(commands.rollup));
gulp.task('rollup:umd', ['scripts'], $.shell.task(commands.rollup));

gulp.task('bundle:umd', ['rollup:umd'], $.shell.task(commands.ts, { ignoreErrors: true }));

Expand Down
18 changes: 0 additions & 18 deletions gulp/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ module.exports.PATHS = {
srcDir: 'src/components/angular2-modal',
pluginDir: 'src/components/angular2-modal/plugins',
tsSrcFiles: 'src/components/angular2-modal/**/*.ts',
tsTestFiles: [

],
releaseAssets: ['LICENSE', 'README.md'],
jsFiles: ['gulpfile.js', 'gulp/*.js'],
tsConfig: path.join(__dirname, '../tsconfig.json'),
tmp: '.tmp/',
dist: {
base: 'dist/',
cjs: 'dist/',
esm: 'dist/esm/',
ts: 'dist/ts/',
bundles: 'dist/bundles/',
}
};
Expand All @@ -38,16 +33,3 @@ module.exports.banner = ['/**',
' * @license <%= pkg.license %>',
' */',
''].join('\n');

// we create the the tsConfig outside the task for fast incremential compilations during a watch.
module.exports.tscConfigCjs = $.typescript.createProject(module.exports.PATHS.tsConfig, {
target: 'ES5',
module: 'commonjs',
moduleResolution: 'node',
declaration: true,
emitDecoratorMetadata: true,
experimentalDecorators: true,
allowJs: true,
outDir: module.exports.PATHS.dist.cjs,
rootDir: module.exports.PATHS.srcDir
});
40 changes: 6 additions & 34 deletions gulp/relative-imports.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
const transform = require('gulp-transform-js-ast');
const rename = require('gulp-es6-imports-renamer');
const replace = require('gulp-replace');

Expand All @@ -15,45 +14,18 @@ function renameFn(originalPath, parentPath, callback) {
}
}

const visitCallExpression = (function() {
function isRequireMethod (path) {
var node = path.value;

return node.type === 'CallExpression' &&
node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'require';
}

function isLiteral(path) {
var args = path.value.arguments;
return args &&
args.length === 1 &&
args[0].type === 'Literal';
}

function isCandidate(path) {
return isRequireMethod(path) && isLiteral(path);
}

return function visitCallExpression(path) {
if (isCandidate(path)) {
var match,
arg = path.value.arguments["0"];
if ((match = CORE_IMPORT_REGEX.exec(arg.value)) !== null) {
arg.value = arg.value.replace(CORE_IMPORT_REGEX, `${CORE_PACKAGE_NAME}$2`);
}
}
return path.value;
}
})();


function tsDefinitionImportRename() {
const CORE_IMPORT_REGEX = /^(import|export)( \{.+\} from ['"])(.*\/components\/angular2-modal)(['"];?)$/mg;
return replace(CORE_IMPORT_REGEX, `$1$2${CORE_PACKAGE_NAME}$4`);
}

function ngcMetadataRename() {
const CORE_IMPORT_REGEX = /(\.\..*?\/components\/angular2-modal)/g;
return replace(CORE_IMPORT_REGEX, `${CORE_PACKAGE_NAME}`);
}

module.exports.tsDefinitionImportRename = tsDefinitionImportRename();
module.exports.ngcMetadataRename = ngcMetadataRename();
module.exports.es6ImportRename = rename({renameFn: renameFn});
module.exports.es5RequireVisitor = transform( { visitCallExpression: visitCallExpression } );
104 changes: 47 additions & 57 deletions gulp/scripts.js
Original file line number Diff line number Diff line change
@@ -1,87 +1,77 @@
const fs = require('fs');
const path = require('path');
const exec = require('child_process').exec;

const del = require('del');
const gulp = require('gulp');
const runSequence = require('run-sequence');
const $ = require('gulp-load-plugins')();
const ngc = require('@angular/compiler-cli');
const config = require('./config');
const merge = require('merge2');
const sourcemaps = require('gulp-sourcemaps');
const relativeImports = require('./relative-imports');

function replaceSrcDir(path) {
path.dirname = path.dirname.replace(/^src\/components\/angular2-modal/ig, ''); // eslint-disable-line no-param-reassign
if (path.dirname.indexOf('dist/esm/plugins/') !== 0) {
path.dirname = 'dist/esm/plugins/' + path.dirname;
}
// path.dirname = path.dirname.replace(/^src\/components\/angular2-modal/ig, ''); // eslint-disable-line no-param-reassign
}


gulp.task('scripts:esm', () => {
const taskConfig = $.typescript.createProject(config.PATHS.tsConfig, {
module: 'ES6',
target: 'ES6',
moduleResolution: 'node',
emitDecoratorMetadata: true,
experimentalDecorators: true,
gulp.task('scripts:esm-ngc', (cb) => {
exec('./node_modules/.bin/ngc -p tsconfig.release.json', function (err, stdout, stderr) {
console.log(stdout);
console.log(stderr);
if (err) {
cb(err);
} else {
// delete all *.ngfactory files.
del.sync(config.PATHS.dist.esm + '**/*.ngfactory.*');
cb();
}
});
});


gulp.task('scripts:esm-rename-js', () => {
// todo: this emit errors right now because of duplicate ES6 declarations.
// should be fixed when https://github.com/angular/angular/issues/4882 is included a new Angular2 version.
const tsResult = gulp.src(config.PATHS.tsSrcFiles)
.pipe($.sourcemaps.init())
.pipe($.typescript(taskConfig, undefined, $.typescript.reporter.nullReporter()));
return tsResult.js

return gulp.src(['dist/esm/plugins/**/*.js'])
.pipe(relativeImports.es6ImportRename)
.pipe($.header(config.banner, {
pkg: config.pkg,
}))
.pipe($.rename(replaceSrcDir))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest(config.PATHS.dist.esm));
.pipe(gulp.dest('.'));
});


gulp.task('scripts:cjs', () => {
// todo: figure out why gulp-typescript don't write to the defined root dir (dist)
const tsResult = gulp.src([config.PATHS.tsSrcFiles, 'typings/browser.d.ts'])
.pipe($.sourcemaps.init())
.pipe($.typescript(config.tscConfigCjs));

return merge([
tsResult.dts
.pipe(relativeImports.tsDefinitionImportRename)
.pipe($.header(config.banner, {
pkg: config.pkg,
}))
.pipe($.rename(replaceSrcDir))
.pipe(gulp.dest(config.PATHS.dist.cjs)),

tsResult.js.pipe($.header(config.banner, {
gulp.task('scripts:esm-rename-dts', () => {
return gulp.src(['dist/esm/plugins/**/*.d.ts'])
.pipe(relativeImports.tsDefinitionImportRename)
.pipe($.header(config.banner, {
pkg: config.pkg,
}))
.pipe(relativeImports.es5RequireVisitor)
.pipe($.rename(replaceSrcDir))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest(config.PATHS.dist.cjs)),
]);
.pipe($.rename(replaceSrcDir))
.pipe(gulp.dest('.'));
});

gulp.task('scripts:test', () => {
const tsResult = gulp.src(config.PATHS.tsTestFiles)
.pipe(sourcemaps.init())
.pipe($.typescript(config.taskConfigCjs));
gulp.task('scripts:esm-rename-ngcMetadata', () => {
return gulp.src(['dist/esm/plugins/**/*.metadata.json'])
.pipe(relativeImports.ngcMetadataRename)
.pipe($.rename(replaceSrcDir))
.pipe(gulp.dest('.'));
});

// todo: figure out why gulp-typescript don't write to the defined root dir (test-built)
function replaceTestDir(path) {
path.dirname = path.dirname.replace('test/', ''); // eslint-disable-line no-param-reassign
}
return merge([
tsResult.dts
.pipe($.header(config.banner, {
pkg: config.pkg,
}))
.pipe($.rename(replaceTestDir))
.pipe(gulp.dest(config.PATHS.testBuilt)),
tsResult.js
.pipe($.rename(replaceTestDir))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest(config.PATHS.testBuilt)),
]);
gulp.task('scripts:esm', (done) => {
runSequence(
['scripts:esm-ngc'],
// plugins requires change to import literals, ../../components/angular2-modal -> angular2-modal
['scripts:esm-rename-js', 'scripts:esm-rename-dts', 'scripts:esm-rename-ngcMetadata'],
done
);
});

gulp.task('scripts', ['scripts:cjs', 'scripts:esm']);
gulp.task('scripts', ['scripts:esm']);
82 changes: 15 additions & 67 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,26 @@
var gulp = require('gulp');
var inlineNg2Template = require('gulp-inline-ng2-template');
var transform = require('gulp-transform-js-ast');

var jsStringEscape = require('js-string-escape');
function doCss(ext, file) {
return jsStringEscape(file);
}

gulp.task('inline-resources', function () {
gulp.src('./dist/build/components/**/*.js')
.pipe(inlineNg2Template({base: './dist/build/', target: 'es5', styleProcessor: doCss}))
.pipe(gulp.dest('./dist/build/components/'));
const del = require('del');
const gulp = require('gulp');
const transform = require('gulp-transform-js-ast');
require('require-dir')('./gulp');
const config = require('./gulp/config');
const runSequence = require('run-sequence');

gulp.src('./dist/build/demo/**/*.js')
.pipe(inlineNg2Template({base: './dist/build/', target: 'es5', styleProcessor: doCss}))
.pipe(gulp.dest('./dist/build/demo/'));
const distPluginPath = { from: 'dist/esm/plugins/**/*', to: 'dist/plugins' };
gulp.task('copyDistPlugins', () => {
return gulp.src(distPluginPath.from)
.pipe(gulp.dest(distPluginPath.to));
});

gulp.task('replace-core-relative-imports', function () {
var CORE_PACKAGE_NAME = 'angular2-modal';
var CORE_IMPORT_REGEX = /^(.*\.\.?\/components\/angular2-modal)(.*)$/;

function isRequireMethod(path) {
var node = path.value;
return node.type === 'CallExpression' &&
node.callee &&
node.callee.type === 'Identifier' &&
node.callee.name === 'require';
}

function isLiteral(path) {
var args = path.value.arguments;
return args &&
args.length === 1 &&
args[0].type === 'Literal';
}

function isCandidate(path) {
return isRequireMethod(path) && isLiteral(path);
}

function visitCallExpression(path) {
if (isCandidate(path)) {
var match,
arg = path.value.arguments["0"];
if ((match = CORE_IMPORT_REGEX.exec(arg.value)) !== null) {
arg.value = arg.value.replace(CORE_IMPORT_REGEX, `${CORE_PACKAGE_NAME}$2`);
}
}
return path.value;
}

gulp.src(['./dist/build/bootstrap.js'])
.pipe(transform({visitCallExpression: visitCallExpression}))
.pipe(gulp.dest('./dist/build'));

gulp.src(['./dist/build/demo/**/*.js'])
.pipe(transform({visitCallExpression: visitCallExpression}))
.pipe(gulp.dest('./dist/build/demo'));

gulp.src(['./dist/build/components/angular2-modal/plugins/**/*.js'])
.pipe(transform({visitCallExpression: visitCallExpression}))
.pipe(gulp.dest('./dist/build/components/angular2-modal/plugins'));
gulp.task('extractPlugins', ['copyDistPlugins'], (done) => {
del.sync('dist/esm/plugins', {force: true});
done();
});


require('require-dir')('./gulp');
const runSequence = require('run-sequence');

gulp.task('build', (done) => {
runSequence(
['clean:dist', 'clean:tmp'],
['copyReleaseAssets', 'scripts', 'bundle'],
'createPackageJson',
['copyReleaseAssets', 'bundle'],
['extractPlugins','createPackageJson'],
done
);
});
Loading

0 comments on commit 9db8f5e

Please sign in to comment.