Home > Software design >  Need Assistance With Blazor and LibMan to install Bootstrap and associated components (i.e., Popper
Need Assistance With Blazor and LibMan to install Bootstrap and associated components (i.e., Popper

Time:10-26

I am working on a Blazor project in which I am using Bootstrap; which, of course, requires jQuery and Popper for the tooltips and popovers to work.

Originally, I just "manually" downloaded the required files:

  • jQuery
  • Popper
  • Bootstrap (css and js)

and put them where they need to go:

  • wwwroot/css
  • wwwroot/js

The structure of wwwroot looked like this:

/wwwroot
|
|- css/
|  |
|  |- bootstrap/
|  |
|  `- site.css
|
|- images/
|
`- js/
   |
   |- bootstrap/
   |
   |- jquery/
   |
   |- popper/
   |
   |- BootstrapJavascript.js
   |
   `- JavaScript.js

However, the "powers that be" have decided they would like to make this more efficient and automatic, so I now need to use LibMan to install everything, and I am using this method:

Solution Explorer -> Project -> Add -> Client-Side Library...

So, everything went smoothly when installing, however I am having trouble with Popper. After installing, wwwroot now looks like this:

/wwwroot
|
|- css/
|  |
|  |- bootstrap*.*
|  |
|  `- site.css
|
|- images/
|
|- js/
|  |
|  |- bootstrap*.*
|  |
|  |- cjs/
|  |
|  |- esm/
|  |
|  |- umd/
|  |
|  `- BootstrapJavascript.js
|
`- scss/

And I am receiving errors indicating that the application cannot find certain libraries or components of libraries.

Originally, when using LibMan to install Popper, LibMan wanted to put Popper here:

wwwroot/lib/popper.js/

However, I elected to put Popper in:

wwwroot/js/

Also, on Bootstraps website, they instruct to pre-load the ability to use tooltips and popovers like this:

// For Bootstrap's Tooltips
// https://getbootstrap.com/docs/5.2/components/tooltips/
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))


// For Bootstrap's Popovers
// https://getbootstrap.com/docs/5.2/components/popovers/
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]')
const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstrap.Popover(popoverTriggerEl))

Which I have in my BootstrapJavascript.js file.

Some of the errors I am getting:

ReferenceError: exports is not defined
    at https://localhost:5003/js/cjs/popper.js:7:23

Error at App.razor:line 48, which is in here:

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/cjs/popper.js"); // THIS IS LINE #48
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/bootstrap.js");
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/BootstrapJavaScript.js");
    }
}

The application was working "perfectly" when I was hand installing Bootstrap, Popper, and jQuery, now it is not.

What do I need to do to get this working like when I was hand-installing?



EDIT:

libman.json

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "library": "[email protected]",
      "destination": "wwwroot/js/jquery/"
    },
    {
      "library": "[email protected]",
      "destination": "wwwroot/js/popper/"
    },
    {
      "library": "[email protected]",
      "destination": "wwwroot/"
    }
  ]
}

App.razor

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/jquery/jquery.min.js");
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/popper/cjs/popper.min.js");
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/bootstrap.min.js");
        await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/BootstrapJavaScript.js");
    }
}

_Host.cshtml:

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="~/" />
    <link rel="stylesheet" href="~/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>

...

    </div>
    <script>
        var blackpearlScript = document.createElement('script');
        blackpearlScript.setAttribute('src', '/js/JavaScript.js');
        document.head.appendChild(blackpearlScript);
    </script>
</body>

CodePudding user response:

I tried to fully explain the general solution that I use in my projects. Probably, your problem are in the definitions of js and css entries.

First of all install LibMan with the below command:

dotnet tool install -g Microsoft.Web.LibraryManager.Cli

The next step is to add a file called libman.json inside the project. To add this file, just enter the following command in the command prompt:

libman init

As you can see, we can also specify the package receiving source, which is set to cdnjs by default, and is actually a Content Delivery Network (CDN) for countless client-side packages. We can also enter our required packages in the libraries array. Even for each package, we can override the provider.

`{"version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [

  ]
}`  

Now, you can get the Jquery, Bootstrap and so on by following command:

libman install bootstrap --provider unpkg --destination wwwroot/lib/bootstrap
libman install jquery --provider unpkg --destination wwwroot/lib/jquery   

Finally, the libman.json file will have below structure:

`{"version": "1.0",
  "defaultProvider": "",
  "libraries": [
 {
  "provider": "cdnjs",
  "library": "[email protected]",
  "destination": "wwwroot/lib/twitter-bootstrap/"
},    
{
  "provider": "unpkg",
  "library": "[email protected]",
  "destination": "wwwroot/lib/jquery/"
}
  ]
}`

After receiving its client-side packages, we will add the relevant entries to the Blazor Server application's Pages \_Layout.cshtml file (or to the Blazor WASM application's wwwroot/index.html file).

    <head>
        <base href="~/" />      
        <link rel="stylesheet" href="lib/twitter- 
            bootstrap/css/bootstrap.min.css" />
    </head>
    <body>
        ..........
        ..........
        <script src="lib/jquery/dist/jquery.min.js"></script>        
        <script src="_framework/blazor.server.js"></script>
    </body>

We define the entry of the css file in the head section and the js file before closing the body tag and of course before <script src="_framework/blazor.server.js"></script> in Blazor Server. There is no need to mention the wwwroot starting folder; Because base href is defined, it points to this folder.

You can also use the libman restore command to reinstall the packages; In this case, just like Nuget, the packages will be downloaded from the libman.json file from the relevant provider and added to the project.

One additional point: You can modify the program's csproj file as follows to automatically run the libman restore command before the build:

   <Project Sdk="Microsoft.NET.Sdk.Web">

      <PropertyGroup>
        <TargetFramework>net5.0</TargetFramework>
      </PropertyGroup>

      <Target Name="DebugEnsureLibManEnv" BeforeTargets="BeforeBuild" Condition=" '$(Configuration)' == 'Debug' ">
        <!-- Ensure libman is installed -->
        <Exec Command="libman --version" ContinueOnError="true">
          <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
        </Exec>
        <Error Condition="'$(ErrorCode)' != '0'" Text="libman is required to build and run this project. To continue, please run `dotnet tool install -g Microsoft.Web.LibraryManager.Cli`, and then restart your command prompt or IDE." />
        <Message Importance="high" Text="Restoring dependencies using 'libman'. This may take several minutes..." />
        <Exec WorkingDirectory="$(MSBuildProjectDirectory)" Command="libman restore" />
      </Target>
    </Project>

EDIT:

According to your comment and edited question:

First, The bootstrap package is installed inside the root of wwwroot.

{
  "library": "[email protected]",
  "destination": "wwwroot/"
}

However, it is referenced in the JS folder.

await JSRuntime.InvokeAsync<IJSObjectReference>("import", "/js/bootstrap.min.js");

Second, please remove the line below from _Host.cshtml:

 <link rel="stylesheet" href="~/css/bootstrap.css" />
   

I suggest that you try to refer to the _Host.cshtml file instead of referring to the OnAfterRenderAsync method, such as below:

<link rel="stylesheet" href="twitter-bootstrap/css/bootstrap.min.css" />

You can do the same for other libraries, such as Popper.

Originally, when using LibMan to install Popper, LibMan wanted to put Popper here

Please try this too. It means the default installation path (/lib) in the libman folder.

I think that all the differences between the code of my project that is running now and the code of your project were these things.

CodePudding user response:

First, I don't know why you put your js files in App.razor, I think it is better ot add them in your MainLayout.razor or _Host.cshtml:

<script src="~/lib/jquery/jquery.min.js"></script>

Second, I don't think that you need to include Popper because Bootstrap has already this library in bootstrap.bundle.js, see this link. You can add this file like this:

Solution Explorer -> right click on Project -> Add -> Client-Side Library -> twitter-bootstrap -> choose specific files -> js -> bootstrap.bundle.min.js.

Please note that the files will be added in lib folder, if you want to change the location, then you need to change your libman.json and I don't think that necessary to change location, just keep them in libfolder.

Then, your script in MainLayout.razor or _Host.cshtml will be:

<script src="~/lib/jquery/jquery.min.js"></script>
<script src="~/lib/twitter-bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="~/js/BootstrapJavaScript.js"></script>
  • Related