{"id":29215348,"url":"https://github.com/shlomiassaf/angular-library-starter","last_synced_at":"2025-07-03T00:09:29.646Z","repository":{"id":76872849,"uuid":"94748984","full_name":"shlomiassaf/angular-library-starter","owner":"shlomiassaf","description":"Your last library starter. A complete, @angular grade, library starter","archived":false,"fork":false,"pushed_at":"2017-11-28T21:49:01.000Z","size":450,"stargazers_count":44,"open_issues_count":14,"forks_count":12,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-04T01:17:27.632Z","etag":null,"topics":["angular","library","starter","typescript","webpack"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shlomiassaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-06-19T07:31:46.000Z","updated_at":"2024-08-16T14:40:07.000Z","dependencies_parsed_at":"2023-04-21T15:08:24.197Z","dependency_job_id":null,"html_url":"https://github.com/shlomiassaf/angular-library-starter","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/shlomiassaf/angular-library-starter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shlomiassaf%2Fangular-library-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shlomiassaf%2Fangular-library-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shlomiassaf%2Fangular-library-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shlomiassaf%2Fangular-library-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shlomiassaf","download_url":"https://codeload.github.com/shlomiassaf/angular-library-starter/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shlomiassaf%2Fangular-library-starter/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263234965,"owners_count":23434922,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["angular","library","starter","typescript","webpack"],"created_at":"2025-07-03T00:09:23.421Z","updated_at":"2025-07-03T00:09:25.898Z","avatar_url":"https://github.com/shlomiassaf.png","language":"TypeScript","readme":"# Angular Library Starter\nThe complete Angular Library starter.\n\n## Features:\n\n  - Minimal configuration. tsconfig, AOT, webpack config are all automated.\n  - Optional Scoping (`npm install @my-scope/my-lib`)\n  - Multiple library repository (` @my-scope/my-lib`, ` @my-scope/her-lib`, ... all in the same repo)\n  - Package extensions.\n  Ship packages with an opt-in internal package (e.g: `@angular/core/testing`), extension are built separately.\n  - Build hooks, tap in to alter package.json, tsconfig, rollup config etc... (globally and per package)\n  - Webpack powered.\n  - Outputs:\n      - Flatten ES Modules (es5, es2015)\n      - Rollup UMD bundle + minified version + gzipped version\n      - Source maps, complete and accurate.\n  - Flat Angular compiler modules - 1 `metadata.json` file.\n  - `@angular` grade npm packages, tree shake compatible.\n  - Resource inlining (html, css, scss) for source code + **metadata.json**\n  - Resource inlining driven by webpack, no fuzzy tasks, use your favourite webpack loaders.\n  - Dedicated demo app, write as if your library is a module (no relative imports)\n  - Simulation mode - Run the demo app on the **prod compiled library** as if its in `node_modules`, in dev or prod mode.\n  - E2E + Simulation - Run E2E in simulation mode\n  - JEST unit testing\n\n---\n\n## Quick start\n**Make sure you have Node version \u003e= 6.0 and NPM \u003e= 3**\n\u003e Clone the repo using same instruction as in [AngularClass/angular-starter](https://github.com/AngularClass/angular-starter)\n\n\n```bash\n# clone the repo\n# --depth 1 removes all but one .git commit history\ngit clone --depth 1 https://github.com/shlomiassaf/angular-library-starter.git\n\n# change directory to the repo\ncd angular-library-starter\n\n# WINDOWS only. In terminal as administrator\nnpm install -g node-pre-gyp\n\n# install the repo with npm\nnpm install\n\n# You can also use yarn\n\n# if you're in China use cnpm\n# https://github.com/cnpm/cnpm\n```\n\nThe repo comes with a demo app and a simple library call **my-lib**\n\nFire up the dev server with both demo app and library bundled in dev mode - JIT.\n\n```bash\nnpm run start\n```\n\ngo to [http://0.0.0.0:3000](http://0.0.0.0:3000) or [http://localhost:3000](http://localhost:3000) in your browser\n\nYou can now make changes to the demo app or the libraries and see it live\nin your browser.\n\n\n## Learn by example:\nGo to [Examples](examples)\n\n\u003e The `DIST_OUTPUT` folder shows the output of the compilation.\n\n## Library commands\n---\n NPM scripts as defined in **angular-starter** did not change.\n The added Library commands are all prefixed with **lib:**\n\n\u003e For example, `npm run test` will fire up karma and run unit tests for **the demo** app.\n`npm run lib:test` will fire up **jest** and run unit tests for libraries only.\n\n---\n\n### lib:sync\n  Sync configuration files.\n  This command align configuration files with the library configuration.\n  Most of the sync concerns path mapping for typescript and jest.\n\n  Run this command after each change to a package configuration that results in a file structure change.\n  This includes adding, removing or changing a package name, Changing the top-level scope, etc..\n\n  The **sync** process rewrites the `paths` mapping in `tsconfig.json`, you\n  can use **hooks** to tap into this process and add custom path mappings.\n  This will make sure that your mappings are re-generated on each rewrite.\n\n\n### lib:build\n  Fires up the build process (release) for all libraries.\n  To run build for a specific library: `npm run lib:build -- --select my-lib`\n\n  Build output for library is in the root folder under `dist_package` folder.**\n\n### lib:build:sim\n  Fires up the **library build process** and once done fires an AOT production\n  build to the demo app **in simulation mode**\n  Simulation mode: The demo app will consume the compiled library and not\n  the source code, having an AOT bundle exactly the same to having the library\n  in `node_modules`. Completely native, no npm link or hard copy to `node_modules`.\n\n  \u003e This command is equivilant to running `lib:build` and then `npm run build:aot:prod -- --env.sim`\n\n### lib:test\n  Run unit tests (JEST) for all libraries.\n\n### lib:test:watch\n  Run unit tests (JEST) in watch mode for all libraries.\n\n### lib:start:sim\n  Fires up the **library build process** and once done fires the dev server\n  with the demo app **in simulation mode**\n\n  This is similar to **lib:build:sim** but the demo application is running\n  in dev mode with JIT compiler. The library however is AOT compiled so\n  it is a good way to test your library, after compilation, working with JIT.\n\n\n---\n\nThe scripts, combined with the original **angular-starter** scripts can compose a full CI process:\n\nFor example, consider the following workflow:\n\n  - `lib:build:sim` - run an AOT build for both lib and demo app\n  - `npm run lib:test` - run library unit tests\n  - `npm run test` - run demo app integration tests (if applicable)\n  - `npm run e2e` - run E2E tests\n\nIf all passes, your library is good to publish.\n\n\u003e E2E tests run on the demo app, make sure to focus your tests on the library\nand it's UI components, less on the demo app.\n\n\n---\n\n## File Structure\nThe root folder for all source files (demo app + libraries) is `/src`\n\nThe demo application is fixed to the directory **demo**\n\nAll other directories under `src` are libraries, the name of each folder\nmust correspond to the value/s in the global library configuration `packages` property.\n\n\u003e For scoped packages, all packages are inside a directory named after the scope and\nthe scope directory is in `src`.\n\nFor the following configuration:\n\n```json\n\"libConfig\": {\n    \"packages\": [\n      \"my-lib\",\n      \"my-lib-N\"\n    ]\n  }\n```\n\nThis should be the file structure:\n\n```\nangular-library-starter/\n ├*─src/                           * Root folder for all source files\n │   ├*─demo/                      * demo app root.\n │   │   ├──index.html             * Index.html: where we generate our index page\n │   │   ├──main.browser.ts        * our entry file for our browser environmen\n │   │   ├──app/                   * WebApp: folder\n │   │   │  └──...                 ╔═══════════════════════════════════╗\n │   │   │                         ║                                   ║\n │   │   ├──styles/                ║ See the angular-starter reop for  ║\n │   │   │                         ║        details information        ║\n │   │   ├──assets/                ║                                   ║\n │   │   └──...                    ╚═══════════════════════════════════╝\n │   │\n │   ├──my-lib/                    * Library root folder\n │   │   ├*─src/                   * Library source code\n │   │   │  ├──...                 * Library content\n │   │   │  ├──module.ts           * NgModule declration module\n │   │   │  └──index.ts            * Library entry files (configurable)\n │   │   │\n │   │   ├──test/                  * Unit tests\n │   │   │  └──...spec.ts\n │   │   │\n │   │   ├──build_hooks.ts         * Local script to intercept and interact with the build process\n │   │   └──package.json           * Local configuration and manifest data\n │   │\n │   │\n │   ├──my-lib-N/                  ╔═══════════════════════════════════╗\n │   │   ├*─src/                   ║      You can manage mutiple       ║\n │   │   │  ├──...                 ║    libraries in the same repo     ║\n │   │   │  ├──module.ts           ║    and/or under the same scope    ║\n │   │   │  └──index.ts            ║                                   ║\n │   │   ├──build_hooks.ts         ║                                   ║\n │   │   └──package.json           ╚═══════════════════════════════════╝\n```\n\nSome notes:\n\n - This is a fairly simple setup. For Scope and extensions scroll down.\n\n - Unit tests are in the `test` folder, sibling to `src`. This is recommendation.\n\n - From the above it comes clear that you can't name a package `demo` (unless it is scoped)\nI believe it should be ok. If however you feel the urge to do so you can start following\nthe configuration files and changing the demo directory into something of your choice.\n\n  - This section focused on the file structure for the code, for a complete\nstructure review for the whole repo see [AngularClass/angular-starter](https://github.com/AngularClass/angular-starter#file-structure)\n\nHere is the output of a single library setup, identical to to above but with only\none library. (my-lib-N is omitted)\n\n![image](https://user-images.githubusercontent.com/5377501/27282174-9299ce48-54f7-11e7-9592-11fb92c0aa24.png)\n\n---\n\n## Library package configuration\n\nThere are 2 locations for configuration:\n\n#### Global Library configuration\n\nDefines the scope (optional) and libraries in this repo.\n\n```ts\nexport interface GlobalLibConfig {\n  scope?: string;\n  packages: string[]\n}\n```\n\n**Global configuration is set in the `package.json` file at the root of this repo**\n```json\n\"libConfig\": {\n    \"packages\": [\n      \"my-lib\"\n    ]\n  }\n```\n\n#### Local Library configuration\n\nDefines the entry point (optional), resource inline and extension libraries for a library..\n\n```ts\nexport interface LocalLibConfig {\n\n  /**\n   * The entry file name, without extension.\n   * defaults to 'index' if not set.\n   *\n   * Use in multi-library configuration to avoid AOT compilation hell with 'index' addition\n   */\n  entry?: string;\n\n  /**\n   * Internal extensions for the library.\n   * If a library declares a \"libExtensions\" property in it's internal package.json file\n   * it is considered as instructions for creating internal umd bundles.\n   *\n   * THIS OBJECT IS SUBJECT TO CHANGE.\n   * Most probably it will be an array of string where metadata for each extension\n   * will be set inside it's package.json and not in the parent.\n   */\n  libExtensions?: Array\u003cLibraryExtension\u003e;\n}\n\n```\n\n**Local configuration is set in the `package.json` file at the root of each library**\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"description\": \"Sample Library\",\n  \"keywords\": [ ],\n  \"libConfig\": {\n    \"inlineResources\": true\n  }\n}\n```\n\n### Scope\nIn npm scope is a simple namespace, here is an example to apply the scope **@king**:\n\n```json\n\"libConfig\": {\n    \"scope\": \"@king\",\n    \"packages\": [\n      \"my-lib\",\n      \"my-lib-N\"\n    ]\n  }\n```\n\nThis should be the file structure:\n\n```\nangular-library-starter/\n ├*─src/\n │   ├*─demo/\n │   │   └──...\n │   └──@king\n │       ├─my-lib/\n │       │  ├*─src/\n │       │  │ ├──...\n │       │  │ ├──module.ts\n │       │  │ └──index.ts\n │       │  ├──build_hooks.ts\n │       │  └──package.json\n │       │\n │       └──my-lib-N/\n │          ├*─src/\n │          │ ├──...\n │          │ ├──module.ts\n │          │ └──index.ts\n │          ├──build_hooks.ts\n │          └──package.json\n```\n\n### Multiple Libraries\n TODO - most of it is already explained.\n\n### Library extensions\nA Library extension is a library inside a library.\nAn extension goes through the same build process a parent library does, the\nonly difference is that it is not published as a unique package, it comes with the parent NPM packages\nand to access it, a deep import URI is required.\n\nFor example, the testing frameworks in each `@angular` package is an internal\npackage, an extension. Not part of the angular package bundle but you can opt-in to it\nif you want.\n\n```ts\nimport { inject, TestBed } from '@angular/core/testing';\n````\n\n**Notice the deep import? this is by design.**\n\nThe `testing` namespace is not part of the `@angular/core` **bundle** even though it might\nseems like it is. An internal of `@angular/core` will be under `@angular/core/src/...`\n\nThe `testing` extension is part of the NPM package but it will not load by default, a specific import URI is required.\n\n\nThe starter adopts this structure.\n\nAn extensions is a top-level path inside the library's root directory that is:\n\n  - Not the `src` directory (which is the main package)\n  - Listed in the **libExtensions** config section in the local configuration\n\nNote the terminology, `top-level path`, it can be a a single directory\nor a path starting from the root of the library.\n\n#### Lets walk through an example:\n\nWe are building a library called **my-lib** and we publish it under the scope `@king`\n\n**my-lib** has 1 extensions and 2 plugins:\n\n  - **testing**\n  - **plug-a**\n  - **plug-b**\n\nWe might have a lot of plugins in the future so we want to group all plugins\ninside a container directory called `plugins`.\n\n\u003e Extensions and plugins are similar in structure, they only differ by their logical intent.\nThe testing extensions is a tool to use while unit testing and not to be included in a production build.\nPlugins are for production, they are opt-in packages that provide functionality to the main package but is not mandatory.\nThis is the terminology I use, you might choose to name it differently.\n\n\n```\nangular-library-starter/\n ├*─src/\n │   ├*─demo/\n │   │   └──...\n │   │\n │   └─@king                        * The scope for all libraries\n │     │\n │     └─my-lib/                    * Main library - root\n │       │\n │       ├*──src/                   * Source code - Main library\n │       │   ├──...\n │       │   ├──module.ts\n │       │   └──my-lib-entry.ts\n │       │\n │       ├───test/                  * Unit tests - Main library (src)\n │       │   └──...spec.ts\n │       │\n │       │          ════════════════════════════════════════════════════\n │       │\n │       ├───testing/               * Testing extension\n │       │   │\n │       │   ├*──src/               * Source code - Testing extension\n │       │   │   ├──...\n │       │   │   ├──module.ts\n │       │   │   └──index.ts\n │       │   │\n │       │   ├───test/              * Unit tests - Testing extension\n │       │   │    └──...spec.ts\n │       │   │\n │       │   ├──build_hooks.ts      * Hook interaction - Testing extension\n │       │   └──package.json\n │       │\n │       │          ════════════════════════════════════════════════════\n │       │\n │       ├───plugins/               * Plugins CONTAINER\n │       │   │\n │       │   ├───plug-a/            * Plug-A extension\n │       │   │   │\n │       │   │   ├*──src/           * Source code - Plug-A extension\n │       │   │   │   ├──...\n │       │   │   │   ├──module.ts\n │       │   │   │   └──index.ts\n │       │   │   │\n │       │   │   ├───test/          * Unit tests - Plug-A extension\n │       │   │   │   └──...spec.ts\n │       │   │   │\n │       │   │   ├──build_hooks.ts  * Hook interaction - Plug-A extension\n │       │   │   └──package.json\n │       │   │\n │       │   │\n │       │   └───plug-b/            * Plug-B extension\n │       │       │\n │       │       ├*──src/           * Source code - Plug-B extension\n │       │       │   ├──...\n │       │       │   ├──module.ts\n │       │       │   └──index.ts\n │       │       │\n │       │       ├───test/          * Unit tests - Plug-B extension\n │       │       │   └──...spec.ts\n │       │       │\n │       │       ├──build_hooks.ts  * Hook interaction - Plug-B extension\n │       │       └──package.json\n │       │\n │       │          ════════════════════════════════════════════════════\n │       │\n │       │\n │       ├──build_hooks.ts          * Hook interaction - Main package\n │       └──package.json\n```\n\n#### The configuration objects\n\n`package.json` (root)\n```json\n\"libConfig\": {\n    \"scope\": \"@king\",\n    \"packages\": [ \"my-lib\" ]\n  }\n```\n\n`src/@king/my-lib/package.json` (library main)\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"description\": \"Sample Library\",\n  \"libConfig\": {\n      \"entry\": \"my-lib-entry\",\n      \"libExtensions\": [\n        {\n          \"name\": \"testing\"\n        },\n        {\n          \"name\": \"plug-a\",\n          \"dir\": \"plugins/plug-a\"\n        },\n        {\n          \"name\": \"plug-b\",\n          \"dir\": \"plugins/plug-b\"\n        }\n      ]\n    }\n}\n```\n\n`src/@king/my-lib/testing/package.json`\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"description\": \"Testing module\"\n}\n```\n\n`src/@king/my-lib/plugins/plug-a/package.json`\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"description\": \"A plugins that is always A\"\n}\n```\n\n`src/@king/my-lib/plugins/plug-b/package.json`\n\n```json\n{\n  \"version\": \"1.0.0\",\n  \"description\": \"A plugins that is always B\"\n}\n```\n\n\nTo access `plug-b` from an angular application:\n```ts\nimport { ... } from '@king/my-lib/plug-b';\n```\n\n### Extensions and bundling:\nBundling FESM and UMD modules requires a manual definition of the dependency graph.\nThis is to prevent duplicate code, so that `my-lib` which uses `@angular/core` will\nnot include `@angular/core` in it's production bundle.\n\nThis is also true for extensions, they are like any other package.\n\nRemember to define the inter-dependency graph for extensions and multi-library configuration\nand of course 3rd party dependencies.\n\nThis is reviewed in-depth in thr **Hooks** section.\n\n---\n\n## Hooks\n  TODO DOCS\n### TL;DR\n\n   - Hooks run using a script, its name is always `build_hooks`\n   - It can be TypeScript or JS file.\n   - Hooks can be global, local or both\n   - **Global Hooks**\n     - Run BEFORE local hooks\n     - `build_hooks` script is in the root of the project\n   - **Local Hooks**\n     - Run AFTER the global hook\n     - `build_hooks` script is in the root of the library (sibling to it's `src` directory)\n\n### Hooks:\n\n#### packageJSON\nExecutes before saving the manifest file but after merging the local manifest with the global manifest.\nParams: package.json object\n\n#### rollupUMD\nExecutes before running the rollup bundling process for UMD.\nParams: Limited Rollup config object\n\n#### rollupFESM\nExecutes before running the rollup bundling process for FESM (es5 and es2015).\nParams: Limited Rollup config object\n\n#### tsconfig\nExecutes before saving `tsconfig.json` to disk and executing webpack.\nUse this hook to modify `tsconfig` before saving it to disk and using it as the compilation configuration.\nParams: tsconfig object\n\n\u003e `lib:sync` invokes the global hook for `tsconfig` with the main `tsconfig.json`.\nSince all other `tsconfig` files inherit from it, use this global hook to add custom paths and TS configuration.\n\n#### jestConfig\nExecutes before saving `jest.library.config.json` to disk.\n\nGLOBAL HOOK only.\n\nParams: jest config object\n\n\u003e `lib:sync` invokes the global hook for `jest.library.config` with the main `jest.library.config.json`.\nThis is the place to add custom JEST configuration and additional (custom) path mappings.\n\n### Hooks blueprint:\n```js\nmodule.exports.packageJSON = function(pkgJson) { };\n\nmodule.exports.jestConfig = function(jestConfig) { };\n\nmodule.exports.tsconfig = function tsconfig(config) {}\n\nmodule.exports.rollupFESM = function(rollupConfig) { };\n\nmodule.exports.rollupUMD = function(rollupConfig) { };\n```\n\n___\n\n## Manifest\n  TODO DOCS\n\n---\n# Based on the amazing work from\n[AngularClass/angular-starter](https://github.com/AngularClass/angular-starter)\n\n___\n\n\n## TODO:\n  - Documentation\n  - Examples for popular scenarios and complex setups\n  - Doc system\n  - Expose release tools to NPM scripts (detect, commit)\n  - Build more release tools\n\n---\n\n# License\n [MIT](/LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshlomiassaf%2Fangular-library-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshlomiassaf%2Fangular-library-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshlomiassaf%2Fangular-library-starter/lists"}