|
| 1 | +# Configuring Bundlers for Packages with CSS Imports |
| 2 | + |
| 3 | +<p class="description">Learn how to configure popular bundlers to correctly handle CSS imports from within npm packages.</p> |
| 4 | + |
| 5 | +When working with npm packages that include CSS imports directly within their files, it's crucial to ensure the project's bundler is correctly configured to handle these styles. This guide provides an overview of how various popular bundlers support such packages and any necessary configuration change required. |
| 6 | + |
| 7 | +## Next.js |
| 8 | + |
| 9 | +### App Router |
| 10 | + |
| 11 | +✅ Works out of the box. |
| 12 | + |
| 13 | +### Pages Router |
| 14 | + |
| 15 | +❌ Configuration change is required. |
| 16 | + |
| 17 | +Add the desired package(s) to the `transpilePackages` array item. |
| 18 | + |
| 19 | +```js title="next.config.mjs" |
| 20 | +const nextConfig = { |
| 21 | + // ...rest of the config |
| 22 | + transpilePackages: ['@mui/x-data-grid'], |
| 23 | +}; |
| 24 | + |
| 25 | +export default nextConfig; |
| 26 | +``` |
| 27 | + |
| 28 | +## Parcel |
| 29 | + |
| 30 | +✅ Works out of the box. |
| 31 | + |
| 32 | +## Rsbuild |
| 33 | + |
| 34 | +✅ Works out of the box. |
| 35 | + |
| 36 | +## Rspack |
| 37 | + |
| 38 | +✅ Works out of the box. |
| 39 | + |
| 40 | +## Vite |
| 41 | + |
| 42 | +### For client side apps |
| 43 | + |
| 44 | +✅ Works out of the box. |
| 45 | + |
| 46 | +### For apps using Vite's SSR |
| 47 | + |
| 48 | +❌ Works with a minor configuration change. |
| 49 | + |
| 50 | +Add the desired packages to `ssr.noExternal` array. |
| 51 | + |
| 52 | +```ts title="vite.config.ts" |
| 53 | +import { defineConfig } from 'vite'; |
| 54 | +// ... |
| 55 | + |
| 56 | +export default defineConfig({ |
| 57 | + plugins: [ |
| 58 | + // plugins, |
| 59 | + ], |
| 60 | + ssr: { |
| 61 | + noExternal: ['@mui/x-data-grid'], |
| 62 | + }, |
| 63 | +}); |
| 64 | +``` |
| 65 | + |
| 66 | +## webpack |
| 67 | + |
| 68 | +❌ Configuration change is required. |
| 69 | + |
| 70 | +We'll have to configure `css-loader` to target CSS files within `node_modules` of the packages. |
| 71 | + |
| 72 | +In both the development and production modes, we'll need to add one more loader to `module.rules` key of the config as shown. |
| 73 | + |
| 74 | +Development mode - |
| 75 | + |
| 76 | +```js title="webpack.config.js" |
| 77 | +module.exports = { |
| 78 | + module: { |
| 79 | + rules: [ |
| 80 | + // rest of the loaders |
| 81 | + { |
| 82 | + test: /node_modules\/(@mui\/x-data-grid|package2)\/(.*)\.css$/, |
| 83 | + use: ['style-loader', 'css-loader'], |
| 84 | + }, |
| 85 | + ], |
| 86 | + }, |
| 87 | +}; |
| 88 | +``` |
| 89 | + |
| 90 | +Make sure that `css-loader` and `style-loader` is already installed. |
| 91 | + |
| 92 | +Production mode - |
| 93 | + |
| 94 | +```js title="webpack.config.js" |
| 95 | +module.exports = { |
| 96 | + module: { |
| 97 | + rules: [ |
| 98 | + // rest of the loaders |
| 99 | + { |
| 100 | + test: /node_modules\/(@mui\/x-data-grid|package2)\/(.*)\.css$/, |
| 101 | + use: [ |
| 102 | + // or add other minifier's loader as per your app |
| 103 | + MiniCssExtractPlugin.loader, |
| 104 | + 'css-loader', |
| 105 | + ], |
| 106 | + }, |
| 107 | + ], |
| 108 | + }, |
| 109 | +}; |
| 110 | +``` |
| 111 | + |
| 112 | +These rules specifically target CSS files within packages inside `node_modules`. If there's already a CSS loader configured for app specific CSS files, make sure to add the `exclude: /node_modules/` key so that the same CSS file doesn't go through both the loaders. |
| 113 | + |
| 114 | +## Node.js |
| 115 | + |
| 116 | +❌ Configuration change is required. |
| 117 | + |
| 118 | +To run scripts directly with Node.js (or Bun) where CSS imports are also involved, we need to configure loader for the runtime to ignore such imports. At the bare minimum, we need a loader file and slight modification to the script invocation. |
| 119 | + |
| 120 | +```js title="loader.js" |
| 121 | +function load(url, context, nextLoad) { |
| 122 | + if (url.substring(url.length - 4) === '.css') { |
| 123 | + return { |
| 124 | + format: 'module', |
| 125 | + shortCircuit: true, |
| 126 | + source: '', |
| 127 | + }; |
| 128 | + } |
| 129 | + |
| 130 | + // Do default loading for other files |
| 131 | + return nextLoad(url, context); |
| 132 | +} |
| 133 | + |
| 134 | +// Or |
| 135 | +// exports.load = load; |
| 136 | +// for CJS |
| 137 | +export { load }; |
| 138 | +``` |
| 139 | + |
| 140 | +and modify the script call - |
| 141 | + |
| 142 | +```json title="package.json" |
| 143 | +{ |
| 144 | + "scripts": { |
| 145 | + "start": "node --loader ./loader.js my-script.js" |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
| 149 | + |
| 150 | +This might log a warning for older Node.js version like - |
| 151 | + |
| 152 | +```bash |
| 153 | +(node:56826) ExperimentalWarning: `--experimental-loader` may be removed in the future; instead use `register()`: |
| 154 | +``` |
| 155 | + |
| 156 | +In that case, the script call would be - |
| 157 | + |
| 158 | +```json title="package.json" |
| 159 | +{ |
| 160 | + "scripts": { |
| 161 | + "start": "node --import 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"./loader.js\", pathToFileURL(\"./\"));' my-script.js" |
| 162 | + } |
| 163 | +} |
| 164 | +``` |
| 165 | + |
| 166 | +## Conclusion |
| 167 | + |
| 168 | +Most modern bundlers handle CSS imports from npm packages quite well, often requiring no extra setup. However, certain setups like webpack or specific server-rendering contexts might need explicit configuration to transpile or correctly process these packages. |
| 169 | + |
| 170 | +Feel free to open a PR to this doc (through `Edit this page` link at the bottom) if certain runtimes or bundler configurations are wrong or missing. |
0 commit comments