9

It is now possible, to get not flat structure of project with ng build, so instead of this:

index.html  
main.bundle.js  
styles.bundle.js  
...

I want scripts to be in subfolder

index.html  
scripts/main.bundle.js  
scripts/styles.bundle.js  
...

I found a topic about this: 'ng build' move scripts to subfolder but hire the solutions is to eject project from cli into webpack but with Angular 7 this is not longer available and ng eject is now disabled:

The 'eject' command has been disabled and will be removed completely in 8.0. The new configuration format provides increased flexibility to modify the configuration of your workspace without ejecting.

There are several projects that can be used in conjuction with the new configuration format that provide the benefits of ejecting without the maintenance overhead. One such project is ngx-build-plus found here: https://github.com/manfredsteyer/ngx-build-plus

Angular provide very poor documentation of angular.json file hire https://github.com/angular/angular-cli/wiki/angular-workspace so it's difficult to use this config file in real project problems.

luiscla27
  • 4,956
  • 37
  • 49
kris_IV
  • 2,396
  • 21
  • 42

2 Answers2

15

You cannot do that by using the ng build command alone, you can do it by using the following the commands one after the other.

ng build --output-path="dist/scripts" --deployUrl="scripts/"

and

move "dist\scripts\index.html" "dist"

The last command works considering that you are using windows (is just a copy/paste, the magic is done by the --deployUrl command).

As stated by @Nick in comments, this options can also be added on your angular.json file:

...
projects: {
  angular: {
     architect: {
        build: {
          options: {
             outputPath: "dist/scripts",
             deployUrl: "scripts/"
          }
        }
     } 
  }
}

Update 09/09/21: Angular updated their documentation from --deployUrl to --deploy-url, they work the same

luiscla27
  • 4,956
  • 37
  • 49
  • 1
    I check your solution and it's almost perfect, so thank you for your help. I had 2 more problems - copy files on different systems, so I use gulp task: (mayby you can add this to your answer) `gulp.task('copy-index', function(done) { var stream = gulp.src('./dist/app/browser/ng-scripts/index.html') .pipe(gulp.dest('./dist/app/browser/')); stream.on('end', function() { done(); }); }); ` and assets location is now different so I need to move it also. – kris_IV Feb 23 '19 at 13:45
  • 1
    These can also be added to the build options in angular.json – Nick Mar 30 '20 at 23:57
  • What about assets? I guess I'll have to use environment for that: srcOn1: string = environment.STATIC_FILES_FOLDER + "assets/start/control_start_blue_over.png"; – Vitaly Sazanovich Sep 09 '21 at 18:11
1

create new file called 'move_assets.js' in the root of the application with the following content.

process.argv.forEach(a => {
  if (a.startsWith('--basepath')){
    basepath = a.split('=')[1];
  }
});
var fs = require('fs');
const { interval } = require('rxjs');

var fileCount = null;

if(!basepath){
  console.error('No basepath provided');
}

console.info('Cleaning up file system... Please wait.');
setTimeout(() => {
  console.info('Deleteing old files...');
  fs.readdir(basepath, (err, files) => {
    if(err) {throw err}
    if (files){
      fileCount = files.length;
      files.forEach(item => {
        if(item !== 'scripts'){
          if(fs.existsSync(basepath + item) && fs.lstatSync(basepath + item).isDirectory()){
            fs.rmdir(basepath + item, { recursive: true }, (err) => { if (err) { throw err; } else {fileCount--;}});
          } else {
            fs.unlink(basepath + item, function (err) { if (err) {throw err} else {fileCount--;} });
          }
        }else {
          fileCount--;
        }
      });
    } else {
      fileCount = 0;
    }
  });
}, 1000); //wait for 1 second for file system to breath :)

var timer = setInterval(() => {

  if (fileCount !== null && fileCount < 1) {

    console.info('Moving files.');

    let i = 0;

    const filesToMove = ['assets', 'index.html', 'favicon.ico']
      filesToMove.forEach(f => {
        if(fs.existsSync(basepath + 'scripts/' + f) && (fs.lstatSync(basepath + 'scripts/' + f).isFile() || fs.lstatSync(basepath + 'scripts/' + f).isDirectory())){
          fs.rename(basepath + 'scripts/' + f, basepath + f,function (err) {
            if (err) {throw err}
            else {
              i++;
              console.info(`Successfully moved ${basepath}scripts/${f} --> ${basepath}${f}`);
              if(i == filesToMove.length){
                console.info('Complete!');
              }
            }
          });
        } else {
          console.error(`Cannot move ${basepath}scripts/${f} - item not found`);
        }
    });

    clearInterval(timer);

  }

},500);

in package.json file add line in scripts section

        "buildWithSubfolder": "ng build --base-href / --deployUrl scripts/ --output-path localfolder/scripts/ && node move_assets.js --basepath=/localfolder/"

this will compile an application and dump all the files in the /scripts folder then move index.html, assets, favicon files to the parent folder.

Clint
  • 973
  • 7
  • 18