简体   繁体   中英

Blazor: How to include npm dependencies into a Razor Class Library?

I am trying to create a Blazor component in a Razor Class Library which uses npm dependencies. In my wwwroot I created a package.json :

{
  "name": "mycomponent",
  "version": "0.0.1",
  "description": "",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "UNLICENSED",
  "dependencies": {
    "d3": "^5.14.2"
  }
}

In my csproj I have:

  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="npm install" WorkingDirectory="$(ProjectDir)wwwroot" />
  </Target>

And I set my project to create a .nupkg.

When I now run dotnet publish MyComponent -c Release , I get the MyComponent.1.0.0.nupkg but its staticwebassets folder only has the top level content of wwwroot in there.

So, how do I get the dependencies from the node_modules folder in there? Do I have to run some sort of packager which generates a minified package in the root folder or am I missing something different?

I found a solution which adds webpack to the game. Here is how I did it:

  1. If you do not already have a package.json , run npm init inside wwwroot to generate one
  2. Move everything in wwwroot but package.json and package-lock.json to wwwroot/src
  3. Install webpack and some loaders:

    npm install --save-dev webpack css-loader file-loader style-loader

  4. Add an appropriate webpack.config.js :

var path = require('path');

module.exports = {
    mode: 'production',
    entry: [ './src/main.js', './src/style.css' ],
    module: {
        rules: [
            { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] },
            { test: /\.(jpe?g|png|gif|svg)$/i, use: 'file-loader' }
        ]
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.bundle.js',
        publicPath: '_content/MyRazorClassLibrary/dist/' // << See note
    }
};

Note: The publicPath is used for rewriting the path when run inside Blazor. Webpack packs the result in a way that all assets are relative to the main JS file. However Blazor expects the data at the path _content/ProjectName , which is accounted for using publicPath .

  1. Add this to the csproj file:
  <Target Name="PreBuild" BeforeTargets="PreBuildEvent">
    <Exec Command="npm install" WorkingDirectory="$(ProjectDir)wwwroot" />
    <Exec Command="webpack" WorkingDirectory="$(ProjectDir)wwwroot" />
  </Target>
  <ItemGroup>
    <Content Remove="wwwroot\package-lock.json" />
    <Content Remove="wwwroot\package.json" />
    <Content Remove="wwwroot\src\**" />
    <Content Remove="wwwroot\webpack.config.js" />
  </ItemGroup>
  <ItemGroup>
    <None Include="wwwroot\package-lock.json" />
    <None Include="wwwroot\package.json" />
    <None Include="wwwroot\src\**" />
    <None Include="wwwroot\webpack.config.js" />
  </ItemGroup>

This will cause the src directory and npm and webpack specific files to not be included in the final NuGet package. Plus, it'll run npm install and webpack .

For this to work, you must install webpack-cli :

npm install -g webpack webpack-cli

Now, when you run dotnet build -c Release MyRazorClassLibrary , and set your library to generate a NuGet package on build, you will get a nice nupkg with everything baked in.

Sorry there is no support for this in Blazor. Your best approach is to document the requirements on external dependencies for anyone using the library.

I'd point out that not everyone uses NPM (I avoid it like the plague) and have different approaches to client-side packages, so if this is a "public" package it might be too prescriptive an approach to require NPM. If it's internal use only that's fine, but you're on your own as to how to handle bundling and packaging.

There is an issue tracking how static resources are handled

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM