diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index 39e0cd2a47..c1376006ac 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -50,7 +50,7 @@ }, { "path": "./dist/js/boosted.js", - "maxSize": "33.75 kB" + "maxSize": "34.0 kB" }, { "path": "./dist/js/boosted.min.js", diff --git a/.cspell.json b/.cspell.json index 228de6cd5c..6dd4c9d1f0 100644 --- a/.cspell.json +++ b/.cspell.json @@ -91,7 +91,6 @@ "popperjs", "Poupard", "prebuild", - "precompiled", "preconnect", "preconnecting", "prefersreducedmotion", diff --git a/config.yml b/config.yml index 8ce957a531..cf9389011b 100644 --- a/config.yml +++ b/config.yml @@ -97,8 +97,8 @@ params: js_hash: "sha384-GBfyQzRj/34bRvjbWfsgvYvEqkV+YniZdXAuu66ZVhSPIdzVzVouXBJBjpd58tcY" js_bundle: "https://cdn.jsdelivr.net/npm/boosted@5.2.0/dist/js/boosted.bundle.min.js" js_bundle_hash: "sha384-NkAB+hiFHsv6dxwL0C4lJtfq1RblxY6+DRFn5QZDpgCdwB5RiOGjaJB0Weq0uCy3" - popper: "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js" - popper_hash: "sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk" + popper: "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js" + popper_hash: "sha384-oBqDVmMz9ATKxIep9tiCxS/Z9fNfEXiDAYTujMAeBAsjFuCZSmKbSSUnQlmh/jp3" focus_visible: "https://cdn.jsdelivr.net/npm/focus-visible@5.2.0/dist/focus-visible.min.js" focus_visible_hash: "sha384-xRa5B8rCDfdg0npZcxAh+RXswrbFk3g6dlHVeABeluN8EIwdyljz/LqJgc2R3KNA" diff --git a/js/src/dropdown.js b/js/src/dropdown.js index 601792953e..424b187ffe 100644 --- a/js/src/dropdown.js +++ b/js/src/dropdown.js @@ -95,7 +95,8 @@ class Dropdown extends BaseComponent { this._popper = null this._parent = this._element.parentNode // dropdown wrapper - this._menu = SelectorEngine.findOne(SELECTOR_MENU, this._parent) + // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/ + this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] this._inNavbar = this._detectNavbar() } @@ -405,7 +406,8 @@ class Dropdown extends BaseComponent { event.preventDefault() - const getToggleButton = SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode) + // todo: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.2/forms/input-group/ + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] const instance = Dropdown.getOrCreateInstance(getToggleButton) if (isUpOrDownEvent) { diff --git a/js/tests/unit/dropdown.spec.js b/js/tests/unit/dropdown.spec.js index 56ac4ff494..ea7ddace30 100644 --- a/js/tests/unit/dropdown.spec.js +++ b/js/tests/unit/dropdown.spec.js @@ -1458,6 +1458,67 @@ describe('Dropdown', () => { }) }) + it('should be able to identify clicked dropdown, even with multiple dropdowns in the same tag', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const dropdownToggle1 = fixtureEl.querySelector('#dropdown1') + const dropdownToggle2 = fixtureEl.querySelector('#dropdown2') + const dropdownMenu1 = fixtureEl.querySelector('#menu1') + const dropdownMenu2 = fixtureEl.querySelector('#menu2') + const spy = spyOn(Dropdown, 'getOrCreateInstance').and.callThrough() + + dropdownToggle1.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle1) + + dropdownToggle2.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle2) + + dropdownMenu1.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle1) + + dropdownMenu2.click() + expect(spy).toHaveBeenCalledWith(dropdownToggle2) + }) + + it('should be able to show the proper menu, even with multiple dropdowns in the same tag', () => { + fixtureEl.innerHTML = [ + '' + ].join('') + + const dropdownToggle1 = fixtureEl.querySelector('#dropdown1') + const dropdownToggle2 = fixtureEl.querySelector('#dropdown2') + const dropdownMenu1 = fixtureEl.querySelector('#menu1') + const dropdownMenu2 = fixtureEl.querySelector('#menu2') + + dropdownToggle1.click() + expect(dropdownMenu1).toHaveClass('show') + expect(dropdownMenu2).not.toHaveClass('show') + + dropdownToggle2.click() + expect(dropdownMenu1).not.toHaveClass('show') + expect(dropdownMenu2).toHaveClass('show') + }) + it('should fire hide and hidden event without a clickEvent if event type is not click', () => { return new Promise(resolve => { fixtureEl.innerHTML = [ diff --git a/package-lock.json b/package-lock.json index 233b339221..65af302908 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,7 +62,7 @@ "vnu-jar": "21.10.12" }, "peerDependencies": { - "@popperjs/core": "^2.11.5" + "@popperjs/core": "^2.11.6" } }, "node_modules/@ampproject/remapping": { @@ -12694,7 +12694,8 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", - "dev": true + "dev": true, + "requires": {} }, "@eslint/eslintrc": { "version": "1.3.1", @@ -13080,7 +13081,8 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true + "dev": true, + "requires": {} }, "agent-base": { "version": "4.3.0", @@ -14648,7 +14650,8 @@ "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true + "dev": true, + "requires": {} } } }, @@ -16766,7 +16769,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.0.0.tgz", "integrity": "sha512-SB8HNNiazAHXM1vGEzf8/tSyEhkfxuDdhYdPBX2Mwgzt0OuF2gicApQ+uvXLID/gXyJQgvrM9+1/2SxZFUUDIA==", - "dev": true + "dev": true, + "requires": {} }, "karma-rollup-preprocessor": { "version": "7.0.7", @@ -18083,13 +18087,15 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", - "dev": true + "dev": true, + "requires": {} }, "postcss-scss": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.4.tgz", "integrity": "sha512-aBBbVyzA8b3hUL0MGrpydxxXKXFZc5Eqva0Q3V9qsBOLEMsjb6w49WfpsoWzpEgcqJGW4t7Rio8WXVU9Gd8vWg==", - "dev": true + "dev": true, + "requires": {} }, "postcss-selector-parser": { "version": "6.0.10", @@ -18105,7 +18111,8 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-7.0.1.tgz", "integrity": "sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==", - "dev": true + "dev": true, + "requires": {} }, "postcss-value-parser": { "version": "4.2.0", @@ -19335,7 +19342,8 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", - "dev": true + "dev": true, + "requires": {} }, "stylelint-config-recommended-scss": { "version": "7.0.0", diff --git a/package.json b/package.json index 68df15515d..d9efb9e15c 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "watch-js-docs": "nodemon --watch site/assets/js/ --ext js --exec \"npm run js-lint\"" }, "peerDependencies": { - "@popperjs/core": "^2.11.5" + "@popperjs/core": "^2.11.6" }, "devDependencies": { "@babel/cli": "^7.18.10", @@ -178,7 +178,7 @@ }, "dependencies": {}, "peerDependencies": { - "@popperjs/core": "^2.11.5" + "@popperjs/core": "^2.11.6" } } } diff --git a/scss/_accordion.scss b/scss/_accordion.scss index 195cc0fa7a..57cc4c88a2 100644 --- a/scss/_accordion.scss +++ b/scss/_accordion.scss @@ -122,6 +122,8 @@ padding: 0 var(--#{$prefix}accordion-body-padding-x) var(--#{$prefix}accordion-body-padding-y) 0; // Boosted mod } +// Boosted mod: no Flush accordion items + // // Boosted mod: // - Sizes diff --git a/site/content/docs/5.2/components/dropdowns.md b/site/content/docs/5.2/components/dropdowns.md index 74e4bd83ab..fce31a0130 100644 --- a/site/content/docs/5.2/components/dropdowns.md +++ b/site/content/docs/5.2/components/dropdowns.md @@ -934,10 +934,10 @@ Regardless of whether you call your dropdown via JavaScript or instead use the d {{< bs-table "table" >}} | Name | Type | Default | Description | | --- | --- | --- | --- | -| `autoClose` | boolean, string | `true` | Configure the auto close behavior of the dropdown: Note: the dropdown can always be closed with the ESC key. | +| `autoClose` | boolean, string | `true` | Configure the auto close behavior of the dropdown: Note: the dropdown can always be closed with the ESC key. | | `boundary` | string, element | `'clippingParents'` | Overflow constraint boundary of the dropdown menu (applies only to Popper's preventOverflow modifier). By default it's `clippingParents` and can accept an HTMLElement reference (via JavaScript only). For more information refer to Popper's [detectOverflow docs](https://popper.js.org/docs/v2/utils/detect-overflow/#boundary). | | `display` | string | `'dynamic'` | By default, we use Popper for dynamic positioning. Disable this with `static`. | -| `offset` | array, string, function | `[0, 2]` | Offset of the dropdown relative to its target. You can pass a string in data attributes with comma separated values like: `data-bs-offset="10,20"`. When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding](https://popper.js.org/docs/v2/modifiers/offset/#skidding-1), [distance](https://popper.js.org/docs/v2/modifiers/offset/#distance-1). For more information refer to Popper's [offset docs](https://popper.js.org/docs/v2/modifiers/offset/#options). | +| `offset` | array, string, function | `[0, 2]` | Offset of the dropdown relative to its target. You can pass a string in data attributes with comma separated values like: `data-bs-offset="10,20"`. When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding](https://popper.js.org/docs/v2/modifiers/offset/#skidding-1), [distance](https://popper.js.org/docs/v2/modifiers/offset/#distance-1). For more information refer to Popper's [offset docs](https://popper.js.org/docs/v2/modifiers/offset/#options). | | `popperConfig` | null, object, function | `null` | To change Boosted's default Popper config, see [Popper's configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it's called with an object that contains the Boosted's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper. | | `reference` | string, element, object | `'toggle'` | Reference element of the dropdown menu. Accepts the values of `'toggle'`, `'parent'`, an HTMLElement reference or an object providing `getBoundingClientRect`. For more information refer to Popper's [constructor docs](https://popper.js.org/docs/v2/constructors/#createpopper) and [virtual element docs](https://popper.js.org/docs/v2/virtual-elements/). | {{< /bs-table >}} diff --git a/site/content/docs/5.2/components/toasts.md b/site/content/docs/5.2/components/toasts.md index 842932aa55..1395da6643 100644 --- a/site/content/docs/5.2/components/toasts.md +++ b/site/content/docs/5.2/components/toasts.md @@ -376,7 +376,7 @@ const toastList = [...toastElList].map(toastEl => new boosted.Toast(toastEl, opt | --- | --- | | `dispose` | Hides an element's toast. Your toast will remain on the DOM but won't show anymore. | | `getInstance` | *Static* method which allows you to get the toast instance associated with a DOM element.
For example: `const myToastEl = document.getElementById('myToastEl')` `const myToast = boosted.Toast.getInstance(myToastEl)` Returns a Boosted toast instance. | -| `getOrCreateInstance` | *Static* method which allows you to get the toast instance associated with a DOM element, or create a new one, in case it wasn't initialized.
`const myToastEl = document.getElementById('myToastEl')` `const myToast = boosted.Toast.getOrCreateInstance(myToastEl)` Returns a Boosted toast instance. | +| `getOrCreateInstance` | *Static* method which allows you to get the toast instance associated with a DOM element, or create a new one, in case it wasn't initialized.
`const myToastEl = document.getElementById('myToastEl')` `const myToast = boosted.Toast.getOrCreateInstance(myToastEl)` Returns a Boosted toast instance. | | `hide` | Hides an element's toast. **Returns to the caller before the toast has actually been hidden** (i.e. before the `hidden.bs.toast` event occurs). You have to manually call this method if you made `autohide` to `false`. | | `isShown` | Returns a boolean according to toast's visibility state. | | `show` | Reveals an element's toast. **Returns to the caller before the toast has actually been shown** (i.e. before the `shown.bs.toast` event occurs). You have to manually call this method, instead your toast won't show. | diff --git a/site/content/docs/5.2/customize/overview.md b/site/content/docs/5.2/customize/overview.md index b332457ffb..ebce753b9b 100644 --- a/site/content/docs/5.2/customize/overview.md +++ b/site/content/docs/5.2/customize/overview.md @@ -53,4 +53,4 @@ Several Boosted components include embedded SVGs in our CSS to style components - [Quantity selector buttons]({{< docsref "/forms/quantity-selector" >}}) - [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. diff --git a/site/content/docs/5.2/getting-started/browsers-devices.md b/site/content/docs/5.2/getting-started/browsers-devices.md index ef20af14f8..5b09cf583a 100644 --- a/site/content/docs/5.2/getting-started/browsers-devices.md +++ b/site/content/docs/5.2/getting-started/browsers-devices.md @@ -30,7 +30,7 @@ Generally speaking, Boosted supports the latest versions of each major platform' | | Chrome | Firefox | Safari | Android Browser & WebView | | --- | --- | --- | --- | --- | | **Android** | Supported | Supported | | v6.0+ | -| **Windows** | Supported | Supported | Supported | | +| **iOS** | Supported | Supported | Supported | | {{< /bs-table >}} ### Desktop browsers diff --git a/site/content/docs/5.2/getting-started/contents.md b/site/content/docs/5.2/getting-started/contents.md index a05360f493..85907fa4b5 100644 --- a/site/content/docs/5.2/getting-started/contents.md +++ b/site/content/docs/5.2/getting-started/contents.md @@ -1,12 +1,12 @@ --- layout: docs title: Contents -description: Discover what's included in Boosted, including our precompiled and source code flavors. +description: Discover what's included in Boosted, including our compiled and source code flavors. group: getting-started toc: true --- -## Precompiled Boosted +## Compiled Boosted Once downloaded, unzip the compressed folder and you'll see something like this: @@ -62,9 +62,9 @@ boosted/ └── boosted.min.js.map ``` -This is the most basic form of Boosted: precompiled files for quick drop-in usage in nearly any web project. We provide compiled CSS and JS (`boosted.*`), as well as compiled and minified CSS and JS (`boosted.min.*`). [Source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`boosted.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`boosted.bundle.js` and minified `boosted.bundle.min.js`) include [Popper](https://popper.js.org/). +This is the most basic form of Boosted: compiled files for quick drop-in usage in nearly any web project. We provide compiled CSS and JS (`boosted.*`), as well as compiled and minified CSS and JS (`boosted.min.*`). [Source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`boosted.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`boosted.bundle.js` and minified `boosted.bundle.min.js`) include [Popper](https://popper.js.org/). -## CSS files +### CSS files Boosted includes a handful of options for including some or all of our compiled CSS. @@ -77,7 +77,7 @@ Boosted includes a handful of options for including some or all of our compiled | `boosted-reboot.css`
`boosted-reboot.rtl.css`
`boosted-reboot.min.css`
`boosted-reboot.rtl.min.css` | — | [Only Reboot]({{< docsref "/content/reboot" >}}) | — | — | {{< /bs-table >}} -## JS files +### JS files Similarly, we have options for including some or all of our compiled JavaScript. @@ -90,7 +90,7 @@ Similarly, we have options for including some or all of our compiled JavaScript. ## Boosted source code -The Boosted source code download includes the precompiled CSS and JavaScript assets, along with source Sass, JavaScript, and documentation. More specifically, it includes the following and more: +The Boosted source code download includes the compiled CSS and JavaScript assets, along with source Sass, JavaScript, and documentation. More specifically, it includes the following and more: ```text boosted/ @@ -108,4 +108,4 @@ boosted/ └── scss/ ``` -The `scss/` and `js/` are the source code for our CSS and JavaScript. The `dist/` folder includes everything listed in the precompiled download section above. The `site/docs/` folder includes the source code for our documentation, and `examples/` of Boosted usage. Beyond that, any other included file provides support for packages, license information, and development. +The `scss/` and `js/` are the source code for our CSS and JavaScript. The `dist/` folder includes everything listed in the compiled download section above. The `site/docs/` folder includes the source code for our documentation, and `examples/` of Boosted usage. Beyond that, any other included file provides support for packages, license information, and development. diff --git a/site/content/docs/5.2/getting-started/contribute.md b/site/content/docs/5.2/getting-started/contribute.md index aed29249b4..7296934091 100644 --- a/site/content/docs/5.2/getting-started/contribute.md +++ b/site/content/docs/5.2/getting-started/contribute.md @@ -28,7 +28,7 @@ Our [package.json]({{< param repo >}}/blob/v{{< param current_version >}}/packag | --- | --- | | `npm start` | Compiles CSS and JavaScript, builds the documentation, and starts a local server. | | `npm run dist` | Creates the `dist/` directory with compiled files. Uses [Sass](https://sass-lang.com/), [Autoprefixer](https://github.com/postcss/autoprefixer), and [terser](https://github.com/terser/terser). | -| `npm test` | Runs tests locally after running `npm run dist` | +| `npm test` | Runs tests locally after running `npm run dist`. | | `npm run docs-serve` | Builds and runs the documentation locally. | {{< /bs-table >}} diff --git a/site/content/docs/5.2/getting-started/download.md b/site/content/docs/5.2/getting-started/download.md index 653ca6c825..00b0021d57 100644 --- a/site/content/docs/5.2/getting-started/download.md +++ b/site/content/docs/5.2/getting-started/download.md @@ -74,7 +74,7 @@ The `boosted` module itself exports all of our plugins. You can manually load Bo Boosted's `package.json` contains some additional metadata under the following keys: - `sass` - path to Boosted's main [Sass](https://sass-lang.com/) source file -- `style` - path to Boosted's non-minified CSS that's been precompiled using the default settings (no customization) +- `style` - path to Boosted's non-minified CSS that's been compiled using the default settings (no customization) {{< callout info >}} {{< partial "callout-info-npm-starter.md" >}} diff --git a/site/content/docs/5.2/getting-started/introduction.md b/site/content/docs/5.2/getting-started/introduction.md index 9d6543d167..7930c7550d 100644 --- a/site/content/docs/5.2/getting-started/introduction.md +++ b/site/content/docs/5.2/getting-started/introduction.md @@ -81,7 +81,7 @@ You can also use the CDN to fetch any of our [additional builds listed in the Co - Read a bit more about some [important global environment settings](#important-globals) that Boosted utilizes. -- Read about what's included in Boosted in our [contents section]({{< docsref "/getting-started/contents#precompiled-boosted" >}}) and the list of [components that require JavaScript](#js-components) below. +- Read about what's included in Boosted in our [contents section]({{< docsref "/getting-started/contents/" >}}) and the list of [components that require JavaScript](#js-components) below. - Need a little more power? Consider building with Boosted by [including the source files via package manager]({{< docsref "/getting-started/download#package-managers" >}}). diff --git a/site/content/docs/5.2/getting-started/javascript.md b/site/content/docs/5.2/getting-started/javascript.md index b6fc72851b..b018719a03 100644 --- a/site/content/docs/5.2/getting-started/javascript.md +++ b/site/content/docs/5.2/getting-started/javascript.md @@ -221,8 +221,8 @@ Every Boosted plugin exposes the following methods and static properties. {{< bs-table "table" >}} | Static property | Description | | --- | --- | -| `NAME` | Returns the plugin name. (Example: `boosted.Tooltip.NAME`) | -| `VERSION` | The version of each of Boosted's plugins can be accessed via the `VERSION` property of the plugin's constructor (Example: `boosted.Tooltip.VERSION`) | +| `NAME` | Returns the plugin name. (Example: `boosted.Tooltip.NAME`) | +| `VERSION` | The version of each of Boosted's plugins can be accessed via the `VERSION` property of the plugin's constructor (Example: `boosted.Tooltip.VERSION`) | {{< /bs-table >}} ## Sanitizer diff --git a/site/content/docs/5.2/getting-started/webpack.md b/site/content/docs/5.2/getting-started/webpack.md index ba6c11b14a..06c3f2d71b 100644 --- a/site/content/docs/5.2/getting-started/webpack.md +++ b/site/content/docs/5.2/getting-started/webpack.md @@ -232,6 +232,93 @@ Importing Boosted into Webpack requires the loaders we installed in the first se Now you can start adding any Boosted 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 Boosted'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 `