I have been trying several ways but I am not able to understand how to generate definition files for my project. I have two angular-cli generated applications A and B, I want A to consume B as a package (with npm link). As far as I understand I need to create an index.ts file in project B with all the modules I want to export and run 'ng build' command. I have seen that only creates the bundles but not the definition files, how can I generate definition files? Is this the correct approach?.
I have tried some other options like 'rollup' and 'ngmakelib' but it seems to be pretty hard to do that simple task. Do we have an easy way to generate Angular 5 projects as libraries and consume that libraries from another projects?
At a high level, here are the steps you would need to do to create a reusable Angular module (all done without webpack):
Create a public_api.ts
file within your src
folder. This should contain all your exported symbols, so that users of your library can do: import { symbol } from 'your-library'
Copy your src
folder to a build/dist
folder making sure to inline your templates. I use gulp
and gulp-inline-ng2-template
for this.
gulpfile.js
const gulp = require('gulp');
const replace = require('gulp-replace');
const inlineNg2Template = require('gulp-inline-ng2-template');
const del = require('del');
gulp.task('clean', function () {
return del([
"dist/**"
], { force: true });
});
gulp.task('copy-public-api', ['clean'], function () {
return gulp.src([
'../src/public_api.ts'
])
.pipe(replace('./app', './src'))
.pipe(gulp.dest('dist'))
});
gulp.task('copy-src', ['copy-public-api'], function () {
return gulp.src([
'../src/app/**/*.ts',
'!../src/app/**/*.spec.ts'
])
.pipe(inlineNg2Template({ base: '../src', useRelativePaths: true }))
.pipe(gulp.dest('dist/src'))
});
public_api.ts
export * from './app/app.module';
// ... other exports ...
ngc
. You'll be using ngc
to generate the necessary metadata files. Here are the settings that I use. The file is placed in a "build" folder (notice the relative paths for typeRoots
and paths
).build/tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"rootDir": ".",
"outDir": "",
"paths": {
"*": [
"../node_modules/*"
]
},
"declaration": true,
"stripInternal": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"module": "es2015",
"target": "es5",
"lib": [
"es2015",
"dom"
],
"skipLibCheck": true,
"typeRoots": [
"../node_modules/@types/"
],
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"sourceMap": true,
"inlineSources": true
},
"files": [
"dist/public_api.ts"
],
"angularCompilerOptions": {
"annotateForClosureCompiler": true,
"strictMetadataEmit": false,
"skipTemplateCodegen": true,
"flatModuleOutFile": "index.js",
"flatModuleId": "ng-module-template"
}
}
The angularCompilerOptions
ensure that one metadata file is created (index.js).
Use ngc
to compile the module from the build folder. Make sure to install @angular/compiler
and @angular/compiler-cli
:
../node_modules/.bin/ngc -p tsconfig.json
Deploy only the files that are needed. I deploy from build\dist
to dist
:
gulp.task('build', [], function (done) {
gulp.src([
'dist/index.js',
'dist/public_api.js',
'dist/index.metadata.json',
'dist/**/*.d.ts',
'!../src/app/**/*.spec.ts'
], { base: 'dist' })
.pipe(gulp.dest('../dist'))
.on('end', function () {
del('dist/**', { force: true }).then(function () {
done();
});
});
});
Make sure you modify your package.json to point to index.js:
{
"name": "ng-module-template",
"version": "1.0.0",
"description": "",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
}
Here is a gulp build target for compiling and creating bundles using rollup with treeshaking:
gulp.task('compile', ['copy-src'], function (done) {
gulp.src('tsconfig.json')
.pipe(shell(['"../node_modules/.bin/ngc" -p <%= file.path %>']))
.on('end', function () {
del('node_modules/**', { force: true }).then(function () {
done();
});
});
});
gulp.task('bundle', ['compile'], function (done) {
var external = [
'@angular/core',
'@angular/common',
'@angular/compiler',
'@angular/core',
'@angular/http',
'@angular/platform-browser',
'@angular/platform-browser-dynamic',
'@angular/router',
'@angular/router-deprecated'
];
var globals = {
'@angular/core': 'vendor._angular_core',
'@angular/http': 'vendor._angular_http',
'@angular/platform-browser': 'vendor._angular_platformBrowser',
'@angular/platform-browser-dynamic': 'vendor._angular_platformBrowserDynamic',
'@angular/router-deprecated': 'vendor._angular_routerDeprecated'
};
rollup.rollup({
input: 'dist/index.js',
onwarn: function (warning) {
if (warning.message.indexOf("treating it as an external dependency") > -1)
return;
console.warn(warning.message);
}
}).then(function (bundle) {
var umd = bundle.write({
file: `dist/bundles/${pkg.name}.umd.js`,
format: 'umd',
exports: 'named',
name: pkg.name,
sourcemap: true,
external: external,
globals: globals
});
var cjs = bundle.write({
file: `dist/bundles/${pkg.name}.cjs.js`,
format: 'cjs',
exports: 'named',
name: pkg.name,
sourcemap: true,
external: external,
globals: globals
});
var amd = bundle.write({
file: `dist/bundles/${pkg.name}.amd.js`,
format: 'amd',
exports: 'named',
name: pkg.name,
sourcemap: true,
external: external,
globals: globals
});
var es = bundle.write({
file: `dist/index.es5.js`,
format: 'es',
exports: 'named',
name: pkg.name,
sourcemap: true,
external: external,
globals: globals
});
return Promise.all([umd, cjs, amd, es]).then(function () {
done();
});
});
});
Pre-requisites
Angular5+
Git (installed locally if you are publishing to a local folder)
https://github.com/angular-patterns/ng-module-template
npm run dev
For development
npm run build
For production app build (outputs to dist folder)
npm run build-module
For a module build (outputs to dist folder)
npm run publish
For publishing to c:\packages
using git. Alternatively, run npm publish
to publish to npm
.
npm run name-module -- --(module-name)
For naming the module. This modifies the source.
npm install c:\packages\<module-name>