ligershark / WebOptimizer

A bundler and minifier for ASP.NET Core
Apache License 2.0
753 stars 113 forks source link

[Bug] Does not work with .NET 6 #232

Open lonix1 opened 2 years ago

lonix1 commented 2 years ago

Environment: .NET 6, Razor Pages, linux

Does not work.

Here is a MINIMAL repro:

Console log:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1] An unhandled exception has occurred while executing the request. System.IO.FileNotFoundException: Could not find file '/foo/bar/MyProject/wwwroot/MyProject.styles.css'. File name: '/foo/bar/MyProject/wwwroot/MyProject.styles.css'

The file wwwroot/MyProject.styles.css is the one dynamically created by RazorPages; I think it's the one related to css isolation.

If I've made a mistake, would appreciate the advice. But I think the above is correct. Coupled with bug in https://github.com/ligershark/WebOptimizer/issues/172, it seems this library does not work with net6.

tchadwick commented 2 years ago

I think the issue is tied to the "TryGetAssetFromRoute" method and the corresponding call to NormalizeRoute in .NET 6. When the asset is added to the pipeline it adds the "/" in front of the asset route, but when the request comes to get the asset, the route is missing the leading "/" resulting in no match. I've tweaked the "NormalizeRoute method with an if statement to put the "/" back in if it was missing and that seems to resolve the issue, but I'm not sure what implications that would have. @madskristensen or anyone else more familiar with the deep inter-workings could validate that it won't break things? (Or I could put it up in a PR if that's preferred)

gumbarros commented 2 years ago

Any alternative for .NET 6?

tchadwick commented 2 years ago

Any alternative for .NET 6?

You can check out my PR for a short-term fix: https://github.com/ligershark/WebOptimizer/pull/240 I think the test just needs to be changed to allow the fix to work, but I also don't know enough about the project as a whole to say if it's the right way to go. I was hoping that someone more familiar with the whole project would step in and point the right direction. All I can say for now is that the proposed fix, when compiled, worked for getting our project up and going with .NET 6. (We use it for js bundling/minification, less compilation, and css bundling/minification)

s3YwCf2ZbfJG4SHAfjQMAjtsf commented 2 years ago

Any news on this and whether the PR gets included?

madskristensen commented 2 years ago

The PR has failing tests. When that is fixed it can be merged

slipdef commented 1 year ago

This is so much a basic thing to be able to handle ASP.NET Core main CSS bundle. MS recommends WebOptimizer as a way to go and it doesn't hadle ASP.NET default stuff - hilarious!

goric commented 1 year ago

It looks like this is only an issue when running the project e.g. via dotnet run or dotnet watch. If I follow the steps in the original post to reproduce, but run dotnet publish and then run the resulting executable, it works.

The root issue seems to be that the ProjectName.styles.css file that ASP.NET generates at build time is placed under a location like obj/Debug/net7.0/scopedcss/bundle/. When the project is published, it's placed in wwwroot/. This is where WebOptimizer looks for using the PhysicalFileProvider, but it can only be found if the project was published. The Microsoft.AspNetCore.StaticWebAssets.ManifestStaticWebAssetFileProvider would be able to locate it when it's in the obj folder, but the logic in GetFileProvider is currently resulting in the PhysicalFileProvider being chosen.

I'm not sure what to do about this though. Should we special-case ProjectName.styles.css such that it's always using the ManifestStaticWebAssetFileProvider? Or give ManifestStaticWebAssetFileProvider a higher precedence over PhysicalFileProvider when the provider is a CompositeFileProvider? Currently it just chooses .Last() as introduced in #238, and before that was just hardcoded to use a PhysicalFileProvider.

StefanOssendorf commented 1 year ago

Hi.

For us it's working (published via dotnet publish and in VS) with the following setup:

  1. Adding AddJavaScriptBundle() and AddBundle()(for css) without specifiying the FileProvider and pre-building a list of available files from the IWebHostEnvironment.WebRootFileProvider.
  2. Not only using app.UseWebOptimizer() (which does not work) but providing the IWebHostEnvironment explicitly as a parameter. This looks something like this:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
    // Do your stuff here
    app.UseWebOptimizer(env);
    // Do more stuff
    }

I don't know why it's working but it's currently working for me. So shrug. HTH someone.

Sidenote: If you use WebOptimizer to bundle js-files for e.g. Blazor WASM (what we do) you have to exclude the dotnet.7.*.js file from the bundling output. Otherwise I always got a corrupt js-file generated which did not work.

LoupaLoupa commented 1 year ago

So, does it work with dotnet 7.0 or not? Documentation is not compatible, would be nice to know if its not supported rapidly as even Microsoft docs seems to point here as a solution.

https://learn.microsoft.com/en-us/aspnet/core/client-side/bundling-and-minification?view=aspnetcore-7.0#choose-a-bundling-and-minification-strategy

lfaletti commented 1 year ago

Hey, in my case I have this setup, resulting in css being bundled, but the js not.. I am a bit frustrated with this tool.

services.AddWebOptimizer(c =>
{
    c.AddCssBundle("/cssbundle.css", "/ie10mobile.css", "/bootstrap.min.css", "/bootstrap-responsive.min.css",
        "/bootstrap-datetimepicker.min.css", "/font-awesome.min.css", "/durandal.css", "/toastr.css");

    c.AddCssBundle("/csslitebundle.css", "/ratchet.min.css", "/featherlight.min.css");

    c.AddJavaScriptBundle("/vendor.js", "/Scripts/rachet.min.js");

});
mizzPpY commented 1 year ago

Hey, in my case I have this setup, resulting in css being bundled, but the js not.. I am a bit frustrated with this tool.

services.AddWebOptimizer(c =>
{
    c.AddCssBundle("/cssbundle.css", "/ie10mobile.css", "/bootstrap.min.css", "/bootstrap-responsive.min.css",
        "/bootstrap-datetimepicker.min.css", "/font-awesome.min.css", "/durandal.css", "/toastr.css");

    c.AddCssBundle("/csslitebundle.css", "/ratchet.min.css", "/featherlight.min.css");

    c.AddJavaScriptBundle("/vendor.js", "/Scripts/rachet.min.js");

});

Hi @lfaletti not sure if you have find a solution for bundling your js files, I able to make it work by using UseContentRoot() method. In your sample it should be something like this:

services.AddWebOptimizer(c =>
{
    c.AddJavaScriptBundle("/vendor.js", "/Scripts/rachet.min.js").UseContentRoot();

});
lcichanowicz commented 1 year ago

This issue is over a year old. Is there any progress? Should we give up hope? Is WebOptimizer dead? (I hope it's not dead.)

s3YwCf2ZbfJG4SHAfjQMAjtsf commented 1 year ago

This issue is over a year old. Is there any progress? Should we give up hope? Is WebOptimizer dead? (I hope it's not dead.)

It takes a little getting used to with the pathing. But seems to work fine with .Net 6 and had updates as recent as 3 months ago. It is also still referred to in the MS Docs.

lcichanowicz commented 1 year ago

It takes a little getting used to with the pathing. But seems to work fine with .Net 6 and had updates as recent as 3 months ago. It is also still referred to in the MS Docs.

Thanks, but what are you referring to with pathing? I followed the setup instructions as best I could, but they've not been updated for .NET 6 (referencing ASP.NET Core 2.0 project in the setup instructions).

I have not tried it with Publish. I tried it with IIS Express in Visual Studio 2022, as I am in early development, and I need it to work as I develop.

s3YwCf2ZbfJG4SHAfjQMAjtsf commented 1 year ago

It takes a little getting used to with the pathing. But seems to work fine with .Net 6 and had updates as recent as 3 months ago. It is also still referred to in the MS Docs.

Thanks, but what are you referring to with pathing? I followed the setup instructions as best I could, but they've not been updated for .NET 6 (referencing ASP.NET Core 2.0 project in the setup instructions).

I have not tried it with Publish. I tried it with IIS Express in Visual Studio 2022, as I am in early development, and I need it to work as I develop.

This was the hard part about implementing this. Lots of trial and error getting the Browser's debugger, Sources tab to show what it should.

bundleVars.RootSourcePath: "" bundleVars.BuilderPath: builder.Environment.ContentRootPath;

        pipeline.AddCssBundle(bundleVars.KendoCssBundle,
            new CssSettings() { MinifyExpressions = bundleVars.IsDevelopment == false },
            $"{bundleVars.RootSourcePath}ci/Content/kendo/{bundleVars.KendoVersion}/kendo.common.min.css",
            $"{bundleVars.RootSourcePath}ci/Content/kendo/{bundleVars.KendoVersion}/kendo.common-bootstrap.min.css",
            $"{bundleVars.RootSourcePath}ci/Content/kendo/{bundleVars.KendoVersion}/kendo.bootstrap-v4.min.css")
            .UseFileProvider(new PhysicalFileProvider(bundleVars.BuilderPath));
lcichanowicz commented 1 year ago

Thanks a lot for sharing. I don't think that is affecting me. I am using CSS files in the standard wwwroot/css directory. You appear to be using Kendo UI, which probably complicates things.

lcichanowicz commented 1 year ago

Update: I got WebOptimizer working in .NET 6 Razor Pages. Effectively, I made no change; I just toggled between IIS Express and Kestrel. Now, it seems to work in both! :]

sur1969 commented 1 year ago

We had the same problem with .net 7 projects, so we wrote our own using gulp and a tag helper. Feel free to use it although it does require some initial setup:

https://github.com/sur1969/BundleMinify

LuohuaRain commented 1 year ago

Hi.

For us it's working (published via dotnet publish and in VS) with the following setup:

  1. Adding AddJavaScriptBundle() and AddBundle()(for css) without specifiying the FileProvider and pre-building a list of available files from the IWebHostEnvironment.WebRootFileProvider.
  2. Not only using app.UseWebOptimizer() (which does not work) but providing the IWebHostEnvironment explicitly as a parameter. This looks something like this:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // Do your stuff here
    app.UseWebOptimizer(env);
    // Do more stuff
}

I don't know why it's working but it's currently working for me. So shrug. HTH someone.

Sidenote: If you use WebOptimizer to bundle js-files for e.g. Blazor WASM (what we do) you have to exclude the dotnet.7.*.js file from the bundling output. Otherwise I always got a corrupt js-file generated which did not work.

It works, thank you. And may I ask how to avoid this warning?

warn: WebOptimizer.AssetBuilder[1005]
      File '/_framework/blazor.server.js' not found. Passing on to next middleware.
MondQ commented 1 year ago

I had an issue with CSS bundles not working in .NET 6. The solution was to use AddBundle instead of AddCssBundle

Before:

pipeline.AddCssBundle(
  "/Content/sass/bundled",
  "Content/sass/bundled.css")
.UseContentRoot();

After:

pipeline.AddBundle(
    "/Content/sass/bundled",
    "text/css; charset=UTF-8",
    "Content/sass/Bundled.css")
.UseContentRoot();
vishalshivan commented 7 months ago

its not working with .net8 for js files.