angular / angular-cli

CLI tool for Angular
https://cli.angular.io
MIT License
26.73k stars 11.98k forks source link

[es-build] Browser directory created in outputPath #26304

Closed ssougnez closed 10 months ago

ssougnez commented 10 months ago

Command

build

Is this a regression?

The previous version in which this bug was not present was

No response

Description

I have an Angular application configure as below:

"outputPath": "../MyNetApplication/wwwroot",

When using webpack build, the compiled files of the Angular application went directly in wwwroot so I could publish my .NET application and it worked directly.

I tried to switch to es-build, however, after the build, the compiled files of the Angular application end up into "../MyNetApplication/wwwroot/browser" which prevents me from publishing the .NET application as this would not work.

It seems weird to me that the outputPath settings of angular.json is only partially honored. According to me, this settings should be used and not altered during the compilation.

Minimal Reproduction

Just create a new Angular application using angular/cli 17 and run ng build. The files will be located under dist/ng17/browser.

Exception or Error

No response

Your Environment

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1700.0
@angular-devkit/build-angular   17.0.0
@angular-devkit/core            17.0.0
@angular-devkit/schematics      17.0.0
@angular/cli                    17.0.0
@schematics/angular             17.0.0
rxjs                            7.8.1
typescript                      5.2.2
zone.js                         0.14.2

Anything else relevant?

No response

alan-agius4 commented 10 months ago

This is by design.

The application builder will output publicly accessible files in the browser directory, ssr files in the server directory and other files such as statistics and licenses information in the root outputPath.

In .NET Core you can configure and change the wwwroot by using .UseWebRoot.

Edit: If this change in outputPath semantics is a major obstacle, consider using browser-esbuild which leverages esbuild/Vite to provide the same build-time improvements as application builder but with identical options to the existing browser builder, meaning outputPath is unchanged.

ssougnez commented 10 months ago

Thanks for the tip.

However, I still find it a bit weird (but maybe I'm alone). If I configure an output path, I expect angular to scrupulously respect it. Especially if I don't use SSR.

What would make more sense to me would be to have a SSR section in the angular.json where I could override the default output path.

This way, people could use the regular outputPath setting to have the same behaviour than with webpack and use a combination of the two if they want to use SSR.

With this approach, everyone would be able to configure his application the way he wants.

Just a suggestion...

alan-agius4 commented 10 months ago

The main reasons behind this change of having a standardise output are;

Whilst this change does remove some flexibility, we believe that the pros outweigh the cons in the long run.

olostan commented 10 months ago

I run in same issue. I am using Firebase for hosting and after moving to application builder when I deploy to hosting, I see that both browser and server folders are deployed, so when I navigate to hosted website I have "not found" as index.html is in browser/index.html

I prefer to use SSR.

It is application builder issue or angularfire? Should I reconfigure Angularfire to deploy only browser folder or server folder or application builder can build into single folder that could be deployed to firebase hosting?

Thnx

alan-agius4 commented 10 months ago

@olostan, if you are using AngulsrFire ng deploy functionality it should determine the right thing out of the box.

Although it does look like they are still working on supporting the new builder https://github.com/firebase/firebase-tools/pull/6480

olostan commented 10 months ago

@alan-agius4 Thnx! Looks like it is exactly what I am missing.

blogcraft commented 10 months ago

Trying to use esbuild has being absolute hell. I don't use ssr (can't even install node in server) but having this browser directory has introduced so many unnecessary problems.

sangphu commented 10 months ago

I am having problem with the browser folder too. I build and output to ../webapp folder in spring boot application. The 'browser' inside ../webapp ruin everything. Developers use Angular to build for many types of applications, not necessarily must use /browser or /server. 'browser' should not be here or at least should have the option not to have it.

pavelpie commented 10 months ago

Big problem for me too. :( Please consider adding an option as a parameter in angular.json. If the parameter is set to an empty string, the output should be directed to just /dist. If the parameter is set to 'browser', then the output should go to the /dist/browser subfolder.

emeryao commented 10 months ago

+1

maybe it's more friendly and a better experience for the developers to make it configurable in addition to the default behavior

Crefelder commented 10 months ago

As a current hack I currently use this. It is strange but works:

Change angular.json: "options": { "outputPath": "dist", Add in angular.json: "architect": { "build": { "configurations": { "production": { "deleteOutputPath": true,

Add in package.json - scripts "postbuild": "node .\\post-build.js",

Add post-build.js file in root: const fs = require('fs-extra'); fs.move('dist/browser', 'dist', (err) => { if(err) { return console.error(err); } });

ChrisCopelandSF commented 10 months ago

+1

Problem here too, I also deploy Angular with a Spring Boot application and all of our pipelines are setup so that Angular builds as part of CI/CD and the output path is set to ../application/src/main/resources/public so that Spring may automatically resolve the view. This change has broken that so we cannot upgrade to Angular 17 without recalibrating all our CI/CD pipelines.

I don't think I even saw this change mentioned in any of the notes, but I may have missed it. If the behaviour isn't going to be looked at/changed/made configurable then maybe it's worth mentioning this more clearly so people upgrading don't blindly cause headaches for themselves.

I agree that there should perhaps be an option for client-side rendering to output in the previous directory structure.

iqmeta commented 10 months ago

I am having problem with the browser folder too. I build and output to ../webapp folder in spring boot application. The 'browser' inside ../webapp ruin everything. Developers use Angular to build for many types of applications, not necessarily must use /browser or /server. 'browser' should not be here or at least should have the option not to have it.

Same here, everything in pipeline is breaking because of forced "BROWSER" folder which does kill of all middleware proxy and base-href stuff set up (eg. relative to ./api json fetch logic) . Please give an option like before to be able to customize the real dist outputPath without forcing devs. Fine with me to have "browser" as default, but give some extra parameter for real outPath of the browser dist... now we need to hack around like @Crefelder

why not in angular.json:

 "outputPath": {
     browser: "../backend/wwwroot/admin",
     ssr: "../backend/not-public-server-side-rendering",
     whatever: "\\server\share\whatever"
}

it's not so easy if you pipe in 5 SPA apps/uis into one wwwroot with the .UseWebRoot .NET change - which also kills of default in C# backend mapping.

dgp1130 commented 10 months ago

If the change in output path is a major obstacle for adopting esbuild/Vite, we recommend using the browser-esbuild builder. This leverages esbuild and Vite for improved build times but keeps the same options as the existing browser builder, meaning outputPath is used directly and no browser sub-directory is created. You can read more on our docs.

To be clear, the motivation behind this change for application builder was to align client and server rendering output which makes it much more intuitive when adding SSR to an existing application in particular. This alignment should make deployments easier and more consistent going forward given the stable paths between CSR and SSR builds. That said, we do recognize the churn to get there, which is why we have browser-esbuild as a compatibility layer to solve this problem so everyone can still see the build performance benefits without having to touch your deployment pipeline.

benbro commented 10 months ago

Building with browser-esbuild show a warning:

The 'browser-esbuild' builder is a compatibility builder which will be removed in a future major version in favor of the 'application' builder.

Will it get removed in the future?

dgp1130 commented 10 months ago

browser-esbuild is stable in v17 and subject to our standard deprecation policy.

@clydin, I wonder we should remove/rephrase that warning? We should definitely prefer application builder, but I'm not sure a warning in a stable builder is the best way of communicating that preference. We could maybe drop "will be removed in a future major version" at minimum just to make it less scary?

blogcraft commented 10 months ago

browser-esbuild keeps throwing errors in Angular 17, it used to work in 16.

10:50:42 [vite] Internal server error: Failed to resolve import "src/environments/environment" from ".angular\vite-root\YourApp\chunk-SHHAMBP3.js". Does the file exist? it just won't work with tsconfig.json "baseUrl": "./",

Lijo123 commented 10 months ago

Upgrading to Angular 17 is now breaking all the spring boot apps. Forcing devs to accommodate a change like this(using the browser folder) rather than making it as an option provides more headaches than solutions. As @Crefelder suggested, now we have to 'hack' our way for a work around. This isn't an ideal solution. Please find a fix to this problem, or at the very least, provide it as an option so it can be configured.

liliyadub commented 10 months ago

I am running into the same issue when upgrading to Angular 17. This forced “BROWSER” directory has introduced a lot of unnecessary problems. Please consider giving an option to be able to customize/configure the dist outputPath.

miakimovich commented 9 months ago

+1

As a temporary solution I have to modify node_modules\@angular-devkit\build-angular\src\tools\esbuild\utils.js file, since it's the only way to output files directly to outputPath specified in angular.json.

Please consider adding an option in angular.json.

dgp1130 commented 9 months ago

I'm seeing a lot of feedback in this thread asking Angular CLI to support an option to drop browser/ from the output path and I want to be very clear: This option already exists!

The browser-esbuild builder is that option. It is designed to be fully backwards-compatible with the existing browser builder and does not create a browser/ subdirectory. It includes all the esbuild/Vite performance benefits of application builder. The only thing browser-esbuild can't do is server-side rendering, however I believe SSR builds have always had the browser/ directory, so if you're having trouble with deployments here, you're probably not using SSR.

If your deployment pipeline is giving you trouble with application builder due to the browser/ directory, then please try browser-esbuild instead. See our docs for more info.

e-oz commented 9 months ago

The browser-esbuild builder is that option

It is deprecated, it's just a temporary solution, not an "option".

ng build says:

The 'browser-esbuild' builder is a compatibility builder which will be removed in a future major version in favor of the 'application' builder.

dgp1130 commented 9 months ago

That log statement was an artifact of prerelease builds. It's already been removed in https://github.com/angular/angular-cli/pull/26402 and should be published today in 17.0.2.

Angular docs state this the best I think:

For existing projects, you can opt-in to use the new builder on a per-application basis with two different options. Both options are considered stable and fully supported by the Angular team. The choice of which option to use is a factor of how many changes you will need to make to migrate and what new features you would like to use in the project.

The application builder is generally preferred as it improves server-side rendered (SSR) builds, and makes it easier for client-side rendered projects to adopt SSR in the future. However it requires a little more migration effort, particularly for existing SSR applications. If the application builder is difficult for your project to adopt, browser-esbuild can be an easier solution which gives most of the build performance benefits with fewer breaking changes.

outputPath is one potential place where application builder can be a little tricky for existing apps, and browser-esbuild is the recommended solution for that right now.

e-oz commented 9 months ago

thank you for the clarification, @dgp1130 !

HCenggel commented 9 months ago

I also encountered the same situation as you, which forced me to make some changes to my project

HCenggel commented 9 months ago

+1

As a temporary solution I have to modify node_modules\@angular-devkit\build-angular\src\tools\esbuild\utils.js file, since it's the only way to output files directly to outputPath specified in angular.json.

Please consider adding an option in angular.json.

helpful to me

markhiserodt commented 9 months ago

For anyone using Asp.Net 8.0 where you have .client and .server subdirectories in your Solution - go to the {solution}.client.esproj file and add add \browser to the like so:

<PublishAssetsDirectory>$(MSBuildProjectDirectory)\dist\{project}\browser</PublishAssetsDirectory>

Then re-deploy and it should fix it

marcusportmann commented 9 months ago

You can add the following to your application.yml file in a Spring Boot application to accommodate the new output path:

spring:
  web:
    resources:
      static-locations: classpath:/static/browser
markgarrigan commented 9 months ago

This is annoying. If I configure an output path, I expect the output path to be what I configured.

HCenggel commented 9 months ago

Is there any new news on this issue?

Shadow5084 commented 9 months ago

Is there any news? i think an option to prevent the browser folder if ssr is not active would be very helpful and easy to do in my opinion

jacekkoziol commented 9 months ago

A configuration option should definitely be added to define the path in which the browser application should be generated - some of the existing projects are already old (they are a few years old). It is a considerable problem to externally change the path (since not always there is direct access to server configuration), from which the files are served.

curlywu commented 9 months ago

as quick fix just move the content under browser one level up, remove the browser directory ... should work

e-oz commented 9 months ago

I'm not sure why you are still asking for news or solutions - @dgp1130 gave an answer, and it works great. Just use browser-esbuild, that’s it, problem solved.

curlywu commented 9 months ago

@e-oz maybe it is not the desired solution?

e-oz commented 9 months ago

@curlywu it is exactly the same as "application", but the "server" part will not be created. And it is exactly what you need if you don't use SSR. And if you do, then you do need browser and server folders.

This issue is closed, so if you need some other feature, I think it is better to create a new issue and explain to Angular devs why the current one can not be used.

curlywu commented 9 months ago

the solution is not sufficiently explained for someone who only has to deal with angular from time to time I now have to sit down again for hours to get it working again

changhuixu commented 9 months ago

@e-oz updating inside of angular.json manually is not an ideal solution. This workaround will eventually be forgotten and not supported.

If using angular cli to generate an application with --ssr=false flag, then angular cli can (and should) honor the --output-path value. It should not be something difficult. Or, Angular team can add another flag in the angular cli and angular.json so that the --output-path does really mean the output path.

My suggestion is that: make this change more visible, also allow customization using the official Angular CLI (instead of manual editing).

e-oz commented 9 months ago

@changhuixu

This workaround will eventually be forgotten and not supported.

No, see this comment.

changhuixu commented 9 months ago

@changhuixu

This workaround will eventually be forgotten and not supported.

No, see this comment.

I don't understand your position here. Are you going to support this workaround? In my opinion, the best way to maintain it is to add a flag in Angular CLI or make Angular CLI smarter. I believe that you are super smart and able to edit angular.json. But I don't trust myself that I could remember it next year after updating Angular to a newer version.

@e-oz , you won't lose anything if Angular CLI becomes better and be able to honor the --output-path value.

e-oz commented 9 months ago

@changhuixu right now there is no such option as --output-path in ng new. outputPath, mentioned by the author of this issue, is part of the angular.json file.

There is one issue with ng new, though. Right now it creates angular.json with @angular-devkit/build-angular:application in the builder field, even if SSR was not selected (or --ssr=false was applied). It is, indeed, a wrong behavior. It should set @angular-devkit/build-angular:browser-esbuild there and generate fields, related to this builder (right now it creates field browser).

Because this issue is already closed, I've created another issue to report this problem.

e-oz commented 9 months ago

I've created a feature request, you might want to track it: https://github.com/angular/angular-cli/issues/26632

e-oz commented 9 months ago

And it's implemented: #26675 🎉 Thank you, @alan-agius4 !

benbro commented 8 months ago

There are already differences between browser-esbuild and application. For example the new "loader" builder option was added to the application builder but not to the browser-esbuild builder. https://github.com/angular/angular-cli/pull/26371

sangphu commented 8 months ago

You can add the following to your application.yml file in a Spring Boot application to accommodate the new output path:

spring:
  web:
    resources:
      static-locations: classpath:/static/browser

Depending on your IDE, this can be an issue. For example, Eclipse will not pick up changes from VSCode, so you will have to manually refresh the Java project to update the web app every time you build or watch your Angular projects. However, if you build to the "webapp" folder, Eclipse will detect the changes automatically.

jsuryakt commented 7 months ago

Fixed in angular >=17.1.x

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            ...}}}

Keep the "browser" : "" value empty if you don't need the default folder browser being added.

https://angular.io/guide/workspace-config#output-path-configuration

joelfcoelho commented 7 months ago

Fixed in angular >=17.1.x

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            ...}}}

Keep the "browser" : "" value empty if you don't need the default folder name browser being added.

https://angular.io/guide/workspace-config#output-path-configuration

This doesn't seem to work for me on 17.1.1. 'browser' is still flagged as required when building

Error: Schema validation failed with the following errors:
Data path "" must have required property 'browser'.

and also can't be an empty string.

An unhandled exception occurred: `browser` option cannot be an empty string.
See "/tmp/ng-PUeaq4/angular-errors.log" for further details.
jsuryakt commented 7 months ago

Fixed in angular >=17.1.x

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            ...}}}

Keep the "browser" : "" value empty if you don't need the default folder name browser being added. https://angular.io/guide/workspace-config#output-path-configuration

This doesn't seem to work for me on 17.1.1. 'browser' is still flagged as required when building

Error: Schema validation failed with the following errors:
Data path "" must have required property 'browser'.

and also can't be an empty string.

An unhandled exception occurred: `browser` option cannot be an empty string.
See "/tmp/ng-PUeaq4/angular-errors.log" for further details.

Can you share the angular.json or configuration

joelfcoelho commented 7 months ago

Fixed in angular >=17.1.x

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            ...}}}

Keep the "browser" : "" value empty if you don't need the default folder name browser being added. https://angular.io/guide/workspace-config#output-path-configuration

This doesn't seem to work for me on 17.1.1. 'browser' is still flagged as required when building

Error: Schema validation failed with the following errors:
Data path "" must have required property 'browser'.

and also can't be an empty string.

An unhandled exception occurred: `browser` option cannot be an empty string.
See "/tmp/ng-PUeaq4/angular-errors.log" for further details.

Can you share the angular.json or configuration

Using @angular-devkit/build-angular:browser-esbuild fixes the issue so I hope this isn't in fact a temporary solution.

But for reference I was using exactly the same options for outputPath you provided.

With

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            ...}}}

I get

Error: Schema validation failed with the following errors:
Data path "" must have required property 'browser'.

And with

"architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:application",
          "options": {
            "outputPath": {
              "base": "dist/project-name",
              "browser": ""
            },
            "browser":"",
            ...}}}

I get

An unhandled exception occurred: `browser` option cannot be an empty string.
See "/tmp/ng-PUeaq4/angular-errors.log" for further details.
joelfcoelho commented 7 months ago

If I don't provide "browser":"" outside of outputPath I see the first error I mentioned. Data path "" must have required property 'browser'.

Like I mentioned though @angular-devkit/build-angular:browser-esbuild works fine for me so no issues there. Just overall a strange decision by the angular team to force @angular-devkit/build-angular:application onto new projects.