{"id":20910901,"url":"https://github.com/wufe/bundle-sink","last_synced_at":"2026-04-21T12:34:55.319Z","repository":{"id":51146616,"uuid":"310851091","full_name":"wufe/bundle-sink","owner":"wufe","description":"Manage static assets within an ASP.NET Core application complying with common encapsulation practices.","archived":false,"fork":false,"pushed_at":"2021-05-21T11:38:52.000Z","size":290,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-23T03:42:21.449Z","etag":null,"topics":["aspnetcore","razor","webpack"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wufe.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-11-07T13:28:38.000Z","updated_at":"2024-01-12T14:47:21.000Z","dependencies_parsed_at":"2022-09-14T04:51:45.094Z","dependency_job_id":null,"html_url":"https://github.com/wufe/bundle-sink","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/wufe/bundle-sink","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wufe%2Fbundle-sink","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wufe%2Fbundle-sink/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wufe%2Fbundle-sink/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wufe%2Fbundle-sink/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wufe","download_url":"https://codeload.github.com/wufe/bundle-sink/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wufe%2Fbundle-sink/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32091994,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-21T11:25:29.218Z","status":"ssl_error","status_checked_at":"2026-04-21T11:25:28.499Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","razor","webpack"],"created_at":"2024-11-18T14:18:19.818Z","updated_at":"2026-04-21T12:34:55.286Z","avatar_url":"https://github.com/wufe.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BundleSink\n\n![.NET Core](https://github.com/Wufe/bundle-sink/workflows/.NET%20Core/badge.svg)\n\nManage static assets within an ASP.NET Core application complying with common encapsulation practices.\n\n***\n\n# Table of contents\n\n* [Getting started](#getting-started)\n    * [Requirements](#requirements)\n    * [Installation](#installation)\n    * [Usage](#usage)\n        * [The result](#the-result)\n        * [Pay attention to execution order](#pay-attention-to-execution-order)\n        * [Rewrite output mode](#rewrite-output-mode)\n* [Additional options](#additional-options)\n    * [Literal entries](#literal-entries)\n    * [Partial builds](#partial-builds)\n\n\n***\n\n# Getting started\n\n\n## Requirements\n\n- The library currently supports `netcoreapp3.1` applications.\n- You need a webpack configuration for your bundles.\n\n\n## Installation\n\n- From the dotnet CLI:  \n`dotnet add package BundleSink`\n\n- Import tag helpers within `_ViewImports.cshtml`:  \n`@addTagHelper *, BundleSink`\n\n- From a command line:\n`npm install bundle-sink-webpack-plugin`\n\n- Update your webpack.config.js adding the plugin:\n```js\nconst BundleSinkWebpackPlugin = require('bundle-sink-webpack-plugin');\n\nmodule.exports = env =\u003e {\n\n    const bundleSinkWebpackPlugin = new BundleSinkWebpackPlugin({\n        output: path.resolve(__dirname, 'client-manifest.json')\n    });\n\n    return {\n        ...,\n        plugins: [\n            ...bundleSinkWebpackPlugin.plugins\n        ]\n    };\n}\n    \n```\n\n- Initialize BundleSink in Program.cs:\n\n```csharp\npublic static IHostBuilder CreateHostBuilder(string[] args) =\u003e\n    Host.CreateDefaultBuilder(args)\n        .ConfigureWebHostDefaults(webBuilder =\u003e\n        {\n            webBuilder\n                .ConfigureBundleSink(builder =\u003e {\n                    builder.WithWebpack(\"client-manifest.json\", \"/dist/\");\n                })\n                .UseStartup\u003cStartup\u003e();\n        });\n```\n\n\u003e The function `WithWebpack` requires two arguments:\n\u003e - The name of the assets manifest created with webpack\n\u003e - The **public** output folder (i.e. the folder under wwwroot where the output is being generated by webpack)\n\n\n## Usage\n\n- Place a sink in your `_Layout.cshtml` or a razor page's \"Scripts\" section:  \n\n*e.g.:  \n\n```razor\n\u003ch1\u003eHomepage\u003c/h1\u003e\n\n@section Scripts {\n    \u003csink /\u003e\n}\n```\n\n- Use a webpack entry from within a partial view / view-component, defining **the name of the entry**\n\n```razor\nThis is a partial view from the homepage\n\n\u003cwebpack-entry name=\"my-homepage-feature\" /\u003e\n```\n\n## The result\nThe `\u003cwebpack-entry\u003e` tag helper marked the specified entry as a dependency.  \nThe `\u003csink\u003e` tag helper uses the dependencies declared all over the razor pages, taking care of duplicates and required chunks\n\nThe html will contain the scripts required for the selected entries, with their hash appended as query string.  \n*e.g.*\n```html\n\u003cscript type=\"text/javascript\" src=\"/dist/my-homepage-feature.js?v=NMaMA8xzap806fSOec7CFpI78hl033lAOIq_Lrr4kmY\"\u003e\u003c/script\u003e\n```\n\n## Pay attention to execution order\n\nThe `\u003csink /\u003e` tag helper must be declared after all the `entries` gets declared, execution order wise.  \n\nThe `_Layout.cshtml` page can contain a `\u003csink /\u003e` tag helper as first istruction and a page imported with the `@RenderBody()` function can contain a `\u003cwebpack-entry /\u003e`, because the `@RenderBody` function delays the execution of the entire layout page:  \nin other words, **the `\u003cwebpack-entry /\u003e` gets called first**.\n\nAt the same time, having the `entry` and the `sink` in the same page source **can prevent the entry to get printed**:  \n\n**Wrong usage**:\n```cshtml\n\u003csink /\u003e\n\u003cwebpack-entry name=\"homepage\"\u003e\n```\n\n**Right usage**:\n```cshtml\n\u003cwebpack-entry name=\"homepage\"\u003e\n\u003csink /\u003e\n```\n\nIf you really need to declare sinks and entries in different ways, you can try enabling the [Rewrite output mode](#rewrite-output-mode).\n\n***\n\n## Rewrite output mode\n\nThere's a mode you can activate that allows to declare entries and sinks in the order you prefer.  \nThis mode is called `RewriteOutput` and can be enabled while configuring bundle sink:\n\n```csharp\nwebBuilder\n    .ConfigureBundleSink(builder =\u003e\n    {\n        builder.RewriteOutput = true;\n        builder.WithWebpack(\"wwwroot/dist/client-manifest.json\", \"/dist/\");\n    });\n```\n\nThis modality is a little **hacky**: mocks the HttpContext.Response.Body to allow it to be read from a custom ResultFilter.  \nThe performance implication of this operation has not been measured.  \n\n**Use it at your own risk.**\n\n***\n\n# Additional options\n\nThe webpack-entry accepts more options in form of attributes\n- Use the attribute `key` if you need an entry to be imported more than once ... Why would you?  (Their dependencies will be imported once)\n- Use the attribute `async` to mark the entry (but not its dependencies) as async\n- Use the attribute `defer` to mark the entry (but not its dependencies) as deferred\n- Use the attribute `css-only` to use css assets only\n- Use the attribute `js-only` to use js assets only\n\n**Named sinks**  \nYou can also render a webpack-entry to a specific sink:\n- Use the `name` attribute on the sink tag helper\n- Use the `sink` attribute on the webpack-entry tag helper\n\n*e.g.*\n```razor\n\u003cwebpack-entry sink=\"ABOVE\" /\u003e\n\u003csink name=\"ABOVE /\u003e\n```\n\n**Dependencies**  \nYou can mark a `\u003cwebpack-entry\u003e` with the `requires` attribute containing a comma separated list of entries required.  \nThese dependencies will be printed before the dependant entry.  \n\nAt the same time you can mark an entry with the `required-by` attribute, which tells the library to prevent printing the entry if no dependants are declared.  \n\n## Literal entries\n\nYou may want to use this library as a native ASPNET Core section, but with added functionalities:  \nyou can use the `\u003cliteral-entry\u003e` tag helper.  \n\nIts usage is the same as native section or environment tag helper.  \n\nThis helper supports `name`, `key`, `sink`, `requires` and `required-by` attributes.\n\n## Partial builds\n\nYou may want to build one entry at a time, in order to speed up development processes.\n\nThe `bundle-sink-webpack-plugin` package provides an option called `partial` which needs to be set to `true` to merge the resulting `client-manifest.json` with the previous one.  \n\nWith `partial: true` the clean plugin gets disabled.  \n\n**Automatic configuration**\n\nThe automatic configuration is provided by the plugin itself.  \nParses the `env` variable passed to the webpack config and checks whether it refers to an existing entry.\n\nThat's how you use it:  \n```js\nconst BundleSinkWebpackPlugin = require('bundle-sink-webpack-plugin');\nmodule.exports = env =\u003e {\n\n    const bundleSinkWebpackPlugin = new BundleSinkWebpackPlugin({\n        clean: true,\n        output: path.resolve(__dirname, 'wwwroot/dist/client-manifest.json'),\n        entry: {\n            'page-a': './page-a/index.ts',\n            'page-b': './page-b/index.ts'\n        },\n        env\n    });\n\n    return {\n        entry: bundleSinkWebpackPlugin.entry,\n        ...ADDITIONAL WEBPACK PARAMETERS,\n        plugins: [\n            ...bundleSinkWebpackPlugin.plugins\n        ]\n    };\n};\n```\n\nYou can call webpack this way:  \n`webpack --config webpack.config.js --env only=page-a`\n\n**Manual configuration**\n\nYou can always **manually** provide the correct `entry` object to webpack and update the bundle-sink options accordingly:  \n(*e.g.*)\n```js\nconst BundleSinkWebpackPlugin = require('bundle-sink-webpack-plugin');\nmodule.exports = env =\u003e {\n\n    let entry = {\n        'page-a': './page-a/index.ts',\n        'page-b': './page-b/index.ts'\n    }\n\n    const bundleSinkOptions = {\n        clean: true,\n        output: path.resolve(__dirname, 'wwwroot/dist/client-manifest.json'),\n        partial: false\n    };\n    \n    if (env['only']) {\n        const selectedEntry = env['only'];\n        if (!entry[selectedEntry]) {\n            throw new Error(`Syntax: --env only=\u003centry name\u003e`);\n        }\n        entry = { [selectedEntry]: entry[selectedEntry] };\n        bundleSinkOptions.partial = true;\n    }\n\n    const bundleSinkWebpackPlugin = new BundleSinkWebpackPlugin(bundleSinkOptions);\n\n    return {\n        entry: entry,\n        ...ADDITIONAL WEBPACK PARAMETERS,\n        plugins: [\n            ...bundleSinkWebpackPlugin.plugins\n        ]\n    };\n};\n```\n\n***","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwufe%2Fbundle-sink","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwufe%2Fbundle-sink","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwufe%2Fbundle-sink/lists"}