Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 building a library with assets

Tags:

Upon building & packaging an Angular 6 library, I can't seem to be able to instruct the Angular CLI to copy the library's assets into the dist/assets folder on every build.

Assuming the project's folder structure is this -

- dist - e2e - node_modules - projects   - lib1     - src       - lib       - assets         - icons - src 

When I run ng build lib1 or ng build lib1 --prod the assets/icons folder is not being copied into dist/lib1/assets/icons.

If I run ng build then src/assets (the root src/assets) is being copied but not projects/lib1/assets.

The angular.json file contains a reference to "assets": ["src/assets"] but it won't allow adding the assets key specifically to the project, only to the main root app. When adding, I get the following error:

Schema validation failed with the following errors: Data path "" should NOT have additional properties(assets).

I also tried adding the following custom copy rule to the assets to copy the assets to dist/lib instead of to dist/appname:

  "assets": [      "src/favicon.ico",      "src/assets",      { "glob": "**/*", "input": "src/assets/icons", "output": "../lib1/assets/icons" }         ], 

But I get the following error:

An asset cannot be written to a location outside of the output path.

Is there a built-in way of managing library asset's copy on every build?

UPDATE 06/05/2018

I opened an issue with Angular CLI regarding this but have not heard back yet. Issue #11701

like image 954
dev7 Avatar asked May 30 '18 03:05

dev7


2 Answers

Currently, I still have not found an official built-in way to do so.

I opened an Angular CLI issue and hopefully will get the CLI team response.

In the meantime my workaround is using command line tools:

In package.json I added:

"scripts": {     ...     "build": "ng build lib1 --prod && scss-bundle -c scss-bundle.config.json && cp -R projects/lib1/src/assets/ dist/lib1/assets/", } 

To copy the SASS files I use scss-bundle with config file scss-bundle.config.json that contains:

{   "entry": "./projects/lib1/src/assets/style/main.scss",   "dest": "./dist/lib1/assets/style/styles.scss" } 

This will build the SASS files of the project into 1 file and copy it into the dist folder. My SASS file structure is something like:

-- projects/lib1/src/assets/                   -- style                      -- main.scss                      -- partials                         -- _variables.scss                         -- _styles.scss                         __ _rtl.scss 

So as you can see I don't want to ship all the raw sass, just one final file. Of course, you can also compile it into a .css file instead.

To make sure all other assets are copied, I use a simple Mac OS/Linux command cp -R or rsync.

And, of course, instead of running ng build I run npm run build.

Hope this helps, and if you have a better solution please let me know.

like image 150
dev7 Avatar answered Sep 28 '22 04:09

dev7


Looks like in the future this can all be automated with the CLI, however, for now, there are a few solutions out there. Some involved writing a post install script, which is a pretty good one if you have a ton of stuff going on. One involves manually moving them over, but that's just way too open for error IMO. I also have seen a couple of npm packages that you can install that seem to extend what ng-packagr does (ng-packagr builds your libraries and webpack builds your apps).

Some of these are good and some are bad, IMO, I won't go into what I think about them individually, instead I'll just share what I do.

I work on an enterprise Angular Application and I'm extracting our features and functionality into Libraries so we can start code sharing with mini-apps in the near future. Because of our processes and build protocols, we are already not using the ng cli directly to build our projects, instead we are using npm scripts.

If you are already familiar with NPM scripts, skip down below, otherwise, this quick note will be super helpful.

With the Angular CLI, you run something like these...

ng build myProject --configuration=production to run a prod build of your project.

ng build myLibrary to run a prod build of your library and you probably run ng build myLibrary --watch=true to run a dev build of your library and watch for changes while you are working on the library.

For me, while I work on the project, I use the ng CLI, just as you do and run ng build myLibrary --watch=true

This works perfectly. I have an assets folder for my libraries that contain assets and I store them in myProject/src/lib/assets. All is well. My assets aren't in my dist/myLibrary though...but hey it's cool, because during development, when I use a relative path in my image tags <img> webpack is pulling from my library project, not my dist folder anyhow. So how do I solve this with an NPM script? Well, when you read the next line, you're going to smack your forehead and go "crap, I knew that"...here goes...

IF SKIPPING, START HERE...

"myLibrary:prod": "ng build myLibrary && mkdir dist/myLibrary/lib/assets && cp -R projects/myLibrary/src/lib/assets/ dist/myLibrary/lib/assets/ && npm run msgAssetsCopied",

Yup, that's it, just some basic bash :)

I'll break it down for those that are new to the command line though.

myLibrary:prod This is the name of the npm script aka npm run script. You call it in the command line with npm run myLibrary:prod and let your terminal do the rest. The "rest" are simply commands your computer terminal can read, interpret and execute accordingly.

ng build myLibrary this triggers the standard ng CLI build command, thus building your library

&& this says "hey after you do the thing to the left of me [&&], do the thing to the right of me"

mkdir dist/myLibrary/lib/assets this one is a basic bash command that creates a directory that you will be copying your assets over to. mkdir makes a directory and the path designates where and what I want that directory to be. If I was in the folder I wanted a directory made in, say "foo", I would do mkdir bar which would give me foo/bar, if I was in "foo" and wanted the directory "tacos" to be in the "bar" directory, I would do mkdir bar/tacos and it would create "tacos" in the "bar" directory like foo/bar/tacos.

I prefer to make a folder and move assets from a -> b, rather than trying to cp a folder and it's assets.

cp -R projects/myLibrary/src/lib/assets/ dist/myLibrary/lib/assets/ this one is broken up into 4 parts for those new to bash.

  1. cp is "copy"
  2. -R is for "recursive", meaning, take all files and folders and keep them the same structure once copied.
  3. projects/myLibrary/src/lib/assets/ this is where my assets are that I want to move over to that new directory I made with the previous mkdir command earlier.
  4. dist/myLibrary/lib/assets/ is the destination for the copy command.

So with this one you have...

  1. Command cp -R
  2. Target path/to/assets/in/library/project/
  3. Destination path/to/desired/directory/in/build

The last step is npm run msgAssetsCopied which is just another npm script in my package.json that tells the person banging on the keyboard that the assets have been copied. I usually have messages throughout my scripts with emojis to make it easier for a dev to see exactly where a script is at any point in time by identifying emojis on the screen. For example...

"msgAssetsCopied": "echo '📁 Assets Copied to Library Dist Folder 📁'",

So 📁 Assets Copied to Library Dist Folder 📁 gets printed in terminal when we are done.

Still new? No worries, now I'll show you where they go in your package.json.

{   "name": "YourWorkspace",   "version": "0.0.0",   "scripts": {     "ng": "ng",     "start": "ng serve",     "build": "ng build",     "test": "ng test",     "lint": "ng lint",     "e2e": "ng e2e",     } }  

As you can see, this is the top of your package.json file. You can add as many scripts as you need, below we'll drop in the one I just shared...

{   "name": "YourWorkspace",   "version": "0.0.0",   "scripts": {     "ng": "ng",     "start": "ng serve",     "build": "ng build",     "test": "ng test",     "lint": "ng lint",     "e2e": "ng e2e",     "myLibrary:prod": "ng build myLibrary && mkdir dist/myLibrary/lib/assets && cp      -R projects/myLibrary/src/lib/assets/ dist/myLibrary/lib/assets/ && npm run      msgAssetsCopied",     } }  

Boom goes the dynamite!

like image 27
anothercoder Avatar answered Sep 28 '22 03:09

anothercoder