Skip to content

Commit

Permalink
Document how to extract CSS, SVG for strict CSP (#36587)
Browse files Browse the repository at this point in the history
* Webpack: explain how to extract CSS from bundle

* Webpack: explain how to extract SVG from bundle

* Update webpack.md

Co-authored-by: Mark Otto <otto@github.com>
  • Loading branch information
charlesroelli and mdo committed Sep 1, 2022
1 parent b5f2d5a commit 4f97d8f
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
2 changes: 1 addition & 1 deletion site/content/docs/5.2/customize/overview.md
Expand Up @@ -48,4 +48,4 @@ Several Bootstrap components include embedded SVGs in our CSS to style component
- [Navbar toggle buttons]({{< docsref "/components/navbar#responsive-behaviors" >}})
- [Select menus]({{< docsref "/forms/select" >}})

Based on [community conversation](https://github.com/twbs/bootstrap/issues/25394), some options for addressing this in your own codebase include replacing the URLs with locally hosted assets, removing the images and using inline images (not possible in all components), and modifying your CSP. Our recommendation is to carefully review your own security policies and decide on the best path forward, if necessary.
Based on [community conversation](https://github.com/twbs/bootstrap/issues/25394), some options for addressing this in your own codebase include [replacing the URLs with locally hosted assets]({{< docsref "/getting-started/webpack#extracting-svg-files" >}}), removing the images and using inline images (not possible in all components), and modifying your CSP. Our recommendation is to carefully review your own security policies and decide on the best path forward, if necessary.
87 changes: 87 additions & 0 deletions site/content/docs/5.2/getting-started/webpack.md
Expand Up @@ -230,6 +230,93 @@ Importing Bootstrap into Webpack requires the loaders we installed in the first

Now you can start adding any Bootstrap components you want to use. Be sure to [check out the complete Webpack example project](https://github.com/twbs/examples/tree/main/webpack) for how to include additional custom Sass and optimize your build by importing only the parts of Bootstrap's CSS and JS that you need.

## Production optimizations

Depending on your setup, you may want to implement some additional security and speed optimizations useful for running the project in production. Note that these optimizations are not applied on [the Webpack example project](https://github.com/twbs/examples/tree/main/webpack) and are up to you to implement.

### Extracting CSS

The `style-loader` we configured above conveniently emits CSS into the bundle so that manually loading a CSS file in `dist/index.html` isn't necessary. This approach may not work with a strict Content Security Policy, however, and it may become a bottleneck in your application due to the large bundle size.

To separate the CSS so that we can load it directly from `dist/index.html`, use the `mini-css-extract-loader` Webpack plugin.

First, install the plugin:

```sh
npm install --save-dev mini-css-extract-plugin
```

Then instantiate and use the plugin in the Webpack configuration:

```diff
--- a/webpack/webpack.config.js
+++ b/webpack/webpack.config.js
@@ -1,8 +1,10 @@
+const miniCssExtractPlugin = require('mini-css-extract-plugin')
const path = require('path')

module.exports = {
mode: 'development',
entry: './src/js/main.js',
+ plugins: [new miniCssExtractPlugin()],
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
@@ -18,8 +20,8 @@ module.exports = {
test: /\.(scss)$/,
use: [
{
- // Adds CSS to the DOM by injecting a `<style>` tag
- loader: 'style-loader'
+ // Extracts CSS for each JS file that includes CSS
+ loader: miniCssExtractPlugin.loader
},
{
```

After running `npm run build` again, there will be a new file `dist/main.css`, which will contain all of the CSS imported by `src/js/main.js`. If you view `dist/index.html` in your browser now, the style will be missing, as it is now in `dist/main.css`. You can include the generated CSS in `dist/index.html` like this:

```diff
--- a/webpack/dist/index.html
+++ b/webpack/dist/index.html
@@ -3,6 +3,7 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel="stylesheet" href="./main.css">
<title>Bootstrap w/ Webpack</title>
</head>
<body>
```

### Extracting SVG files

Bootstrap's CSS includes multiple references to SVG files via inline `data:` URIs. If you define a Content Security Policy for your project that blocks `data:` URIs for images, then these SVG files will not load. You can get around this problem by extracting the inline SVG files using Webpack's asset modules feature.

Configure Webpack to extract inline SVG files like this:

```diff
--- a/webpack/webpack.config.js
+++ b/webpack/webpack.config.js
@@ -16,6 +16,14 @@ module.exports = {
},
module: {
rules: [
+ {
+ mimetype: 'image/svg+xml',
+ scheme: 'data',
+ type: 'asset/resource',
+ generator: {
+ filename: 'icons/[hash].svg'
+ }
+ },
{
test: /\.(scss)$/,
use: [
```

After running `npm run build` again, you'll find the SVG files extracted into `dist/icons` and properly referenced from CSS.

{{< markdown >}}
{{< partial "guide-footer.md" >}}
{{< /markdown >}}

0 comments on commit 4f97d8f

Please sign in to comment.