28

The property apps in the angular-cli.json file is of array type. If I add a second element into this array, how can I instruct ng build to build both elements?

7 Answers 7

11

Currently v1.0.0 you can only select app which you want to build by the following command:

ng build -a appName

or

ng build --app appName

you also will need to add name property to each element in the apps array so you will have something like that:

"apps": [ { "name": "app1", "root": "src/app1root", ... }, { "name": "app2", "root": "src/app2root", ... }, ... ]

also you can use app indices like ng build -a 0 or ng build -a 1 in that case you don't need to specify app names.

From angular-cli sorces you can see that there is no possibility to run all apps in one command, you should either specify index either app name otherwise apps[0] will be used, so you can't build all apps at the same time using one ng build call.

Sign up to request clarification or add additional context in comments.

Comments

9

Use your package.json:

"scripts": {
   "build-projects": "ng build project1 && ng build project2",
}

Then run: npm run build projects.

Comments

5

I searched the angular-cli source code but could not find any reference to code that iterates or otherwise inspects the contents of apps as an array.

As of now (angular-cli version 1.0.0-beta.15), every instance of code that deals with apps uses the first element of the array hardcoded (apps[0]). There does not seem to be a way to select an app to build or alter the default behaviour of using the first element of the array.

The JSON schema for the apps element describes it this way:

Properties of the different applications in this project.

/**
 * Properties of the different applications in this project.
 */
apps?: {
    root?: string;
    outDir?: string;
    assets?: string;
    index?: string;
    main?: string;
    test?: string;
    tsconfig?: string;
    prefix?: string;
    mobile?: boolean;
    /**
     * Global styles to be included in the build.
     */
    styles?: string[];
    /**
     * Global scripts to be included in the build.
     */
    scripts?: string[];
    /**
     * Name and corresponding file for environment config.
     */
    environments?: {
        [name: string]: any;
    };
}[];

It seems to be a future intent of the project to support building multiple apps out of the same code base but it does not look like it is something doable right now (1.0.0-beta.15 version).

4 Comments

Ok, I will leave the question open hoping the angular-cli developers implement it in the near future.
I find angular-cli's lack of documentation disturbing
@Kamaruni I think so too. My hope is that they will make it better over time, especially now that Angular 2 final is out. There's at least the Github page: github.com/angular/angular-cli And don't forget the Wiki: github.com/angular/angular-cli/wiki
@Readren please accept an answer and to get angular-cli team attention, you should open an issue/enhancement with them in github :)
4

As of October 28th, 2019 the proper way from the docs to build a specific project:

ng build <app name>

There is an open issue in GitHub to add an ability to build multiple projects at once.

Comments

3

Still there isn't any flag for ng build --app to build all apps with one command, so best way to solve this is to create Makefile file in root of project:

my-app
  --dist/
  --e2e/
  --src/
  .angular-cli.json
  package.json
  Makefile 

Makefiles allows to organize code compilation according of instructions you provided. So we need to provide instruction to build frontend for all apps into an output directory. Now Makefile file looks like this:

help:
    @echo "_______BUILD ANGULAR FRONTEND______\n"
    @echo "To build all apps run make make build-frontend"

build-frontend:
    ng build -a=0 &&\
    ng build -a=1 

However after you copy-paste code above, change spaces into tab. Otherwise you will get invalid Makefile with *** missing separator error

Navigate to root project and just to test, type make in terminal and you should get help message printed. After that type:

make build-frontend

Now you have multiple apps build with just one command.

1 Comment

Cmdline does not recognize make command. Do I need to install some cli tool to use it?
1

I also answered a similar question here -> Angular 6 CLI -> how to make ng build build project + libraries

This is for >= ng6. If you'd like something for older versions of the cli, you can take a look at this version -> https://gist.github.com/bmarti44/f6b8d3d7b331cd79305ca8f45eb8997b/03c3b788551cd43db38d2f48e207a730aaba5b6f

I created a script that, when placed in the same folder as angular.json, will pull in the file, loop over the projects, and build them in batches asynchronously.

Here's a quick gist, you can toggle the output path and the number of asynchronous builds. I've excluded e2e for the moment, but you can remove the reference to the filteredProjects function, and it will run for e2e as projects as well. It would also be easy to add this to package.json as an npm run script. So far, it has been working well.

https://gist.github.com/bmarti44/f6b8d3d7b331cd79305ca8f45eb8997b

const fs = require('fs'),
  spawn = require('child_process').spawn,
  // Custom output path.
  outputPath = '/nba-angular',
  // Number of projects to build asynchronously.
  batch = 3;

let ngCli;

function buildProject(project) {
  return new Promise((resolve, reject) => {
    let child = spawn('ng', ['build', '--project', project, '--prod', '--extract-licenses', '--build-optimizer', `--output-path=${outputPath}/dist/` + project]);

    child.stdout.on('data', (data) => {
      console.log(data.toString());
    });

    child.stderr.on('data', (data) => {
      process.stdout.write('.');
    });

    child.on('close', (code) => {
      if (code === 0) {
        resolve(code);
      } else {
        reject(code);
      }
    });
  })
}

function filterProjects(projects) {
  return Object.keys(projects).filter(project => project.indexOf('e2e') === -1);
}

function batchProjects(projects) {
  let currentBatch = 0,
    i,
    batches = {};

  for (i = 0; i < projects.length; i += 1) {
    if ((i) % batch === 0) {
      currentBatch += 1;
    }
    if (typeof (batches['batch' + currentBatch]) === 'undefined') {
      batches['batch' + currentBatch] = [];
    }

    batches['batch' + currentBatch].push(projects[i]);
  }
  return batches;
}

fs.readFile('angular.json', 'utf8', async (err, data) => {
  let batches = {},
    batchesArray = [],
    i;

  if (err) {
    throw err;
  }

  ngCli = JSON.parse(data);

  batches = batchProjects(filterProjects(ngCli.projects));
  batchesArray = Object.keys(batches);

  for (i = 0; i < batchesArray.length; i += 1) {
    let promises = [];

    batches[batchesArray[i]].forEach((project) => {
      promises.push(buildProject(project));
    });

    console.log('Building projects ' + batches[batchesArray[i]].join(','));

    await Promise.all(promises).then(statusCode => {
      console.log('Projects ' + batches[batchesArray[i]].join(',') + ' built successfully!');
      if (i + 1 === batchesArray.length) {
        process.exit(0);
      }
    }, (reject) => {
      console.log(reject);
      process.exit(1);
    });
  }
});

Comments

0

For Angular 6+:

**Dev build**

ng build --project="second-app"

**Prod build**

ng build --configuration production --project="second-app"

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.