1 | <div align="center">
|
2 | <a href="https://github.com/webpack/webpack">
|
3 | <img width="200" height="200" src="https://webpack.js.org/assets/icon-square-big.svg">
|
4 | </a>
|
5 | </div>
|
6 |
|
7 | [![npm][npm]][npm-url]
|
8 | [![node][node]][node-url]
|
9 | [![tests][tests]][tests-url]
|
10 | [![cover][cover]][cover-url]
|
11 | [![discussion][discussion]][discussion-url]
|
12 | [![size][size]][size-url]
|
13 |
|
14 | # less-loader
|
15 |
|
16 | A Less loader for webpack. Compiles Less to CSS.
|
17 |
|
18 | ## Getting Started
|
19 |
|
20 | To begin, you'll need to install `less` and `less-loader`:
|
21 |
|
22 | ```console
|
23 | npm install less less-loader --save-dev
|
24 | ```
|
25 |
|
26 | or
|
27 |
|
28 | ```console
|
29 | yarn add -D less less-loader
|
30 | ```
|
31 |
|
32 | or
|
33 |
|
34 | ```console
|
35 | pnpm add -D less less-loader
|
36 | ```
|
37 |
|
38 | Then add the loader to your `webpack` config. For example:
|
39 |
|
40 | **webpack.config.js**
|
41 |
|
42 | ```js
|
43 | module.exports = {
|
44 | module: {
|
45 | rules: [
|
46 | {
|
47 | test: /\.less$/i,
|
48 | use: [
|
49 | // compiles Less to CSS
|
50 | "style-loader",
|
51 | "css-loader",
|
52 | "less-loader",
|
53 | ],
|
54 | },
|
55 | ],
|
56 | },
|
57 | };
|
58 | ```
|
59 |
|
60 | And run `webpack` via your preferred method.
|
61 |
|
62 | ## Options
|
63 |
|
64 | - **[`lessOptions`](#lessoptions)**
|
65 | - **[`additionalData`](#additionalData)**
|
66 | - **[`sourceMap`](#sourcemap)**
|
67 | - **[`webpackImporter`](#webpackimporter)**
|
68 | - **[`implementation`](#implementation)**
|
69 |
|
70 | ### `lessOptions`
|
71 |
|
72 | Type:
|
73 |
|
74 | ```ts
|
75 | type lessOptions = import('less').options | ((loaderContext: LoaderContext) => import('less').options})
|
76 | ```
|
77 |
|
78 | Default: `{ relativeUrls: true }`
|
79 |
|
80 | You can pass any Less specific options to the `less-loader` through the `lessOptions` property in the [loader options](https://webpack.js.org/configuration/module/#rule-options-rule-query). See the [Less documentation](http://lesscss.org/usage/#command-line-usage-options) for all available options in dash-case. Since we're passing these options to Less programmatically, you need to pass them in camelCase here:
|
81 |
|
82 | #### `object`
|
83 |
|
84 | Use an object to pass options through to Less.
|
85 |
|
86 | **webpack.config.js**
|
87 |
|
88 | ```js
|
89 | module.exports = {
|
90 | module: {
|
91 | rules: [
|
92 | {
|
93 | test: /\.less$/i,
|
94 | use: [
|
95 | {
|
96 | loader: "style-loader",
|
97 | },
|
98 | {
|
99 | loader: "css-loader",
|
100 | },
|
101 | {
|
102 | loader: "less-loader",
|
103 | options: {
|
104 | lessOptions: {
|
105 | strictMath: true,
|
106 | },
|
107 | },
|
108 | },
|
109 | ],
|
110 | },
|
111 | ],
|
112 | },
|
113 | };
|
114 | ```
|
115 |
|
116 | #### `function`
|
117 |
|
118 | Allows setting the options passed through to Less based off of the loader context.
|
119 |
|
120 | ```js
|
121 | module.exports = {
|
122 | module: {
|
123 | rules: [
|
124 | {
|
125 | test: /\.less$/i,
|
126 | use: [
|
127 | "style-loader",
|
128 | "css-loader",
|
129 | {
|
130 | loader: "less-loader",
|
131 | options: {
|
132 | lessOptions: (loaderContext) => {
|
133 | // More information about available properties https://webpack.js.org/api/loaders/
|
134 | const { resourcePath, rootContext } = loaderContext;
|
135 | const relativePath = path.relative(rootContext, resourcePath);
|
136 |
|
137 | if (relativePath === "styles/foo.less") {
|
138 | return {
|
139 | paths: ["absolute/path/c", "absolute/path/d"],
|
140 | };
|
141 | }
|
142 |
|
143 | return {
|
144 | paths: ["absolute/path/a", "absolute/path/b"],
|
145 | };
|
146 | },
|
147 | },
|
148 | },
|
149 | ],
|
150 | },
|
151 | ],
|
152 | },
|
153 | };
|
154 | ```
|
155 |
|
156 | ### `additionalData`
|
157 |
|
158 | Type:
|
159 |
|
160 | ```ts
|
161 | type additionalData =
|
162 | | string
|
163 | | ((content: string, loaderContext: LoaderContext) => string);
|
164 | ```
|
165 |
|
166 | Default: `undefined`
|
167 |
|
168 | Prepends/Appends `Less` code to the actual entry file.
|
169 | In this case, the `less-loader` will not override the source but just **prepend** the entry's content.
|
170 |
|
171 | This is especially useful when some of your Less variables depend on the environment:
|
172 |
|
173 | > Since you're injecting code, this will break the source mappings in your entry file. Often there's a simpler solution than this, like multiple Less entry files.
|
174 |
|
175 | #### `string`
|
176 |
|
177 | ```js
|
178 | module.exports = {
|
179 | module: {
|
180 | rules: [
|
181 | {
|
182 | test: /\.less$/i,
|
183 | use: [
|
184 | "style-loader",
|
185 | "css-loader",
|
186 | {
|
187 | loader: "less-loader",
|
188 | options: {
|
189 | additionalData: `@env: ${process.env.NODE_ENV};`,
|
190 | },
|
191 | },
|
192 | ],
|
193 | },
|
194 | ],
|
195 | },
|
196 | };
|
197 | ```
|
198 |
|
199 | #### `function`
|
200 |
|
201 | ##### `Sync`
|
202 |
|
203 | ```js
|
204 | module.exports = {
|
205 | module: {
|
206 | rules: [
|
207 | {
|
208 | test: /\.less$/i,
|
209 | use: [
|
210 | "style-loader",
|
211 | "css-loader",
|
212 | {
|
213 | loader: "less-loader",
|
214 | options: {
|
215 | additionalData: (content, loaderContext) => {
|
216 | // More information about available properties https://webpack.js.org/api/loaders/
|
217 | const { resourcePath, rootContext } = loaderContext;
|
218 | const relativePath = path.relative(rootContext, resourcePath);
|
219 |
|
220 | if (relativePath === "styles/foo.less") {
|
221 | return "@value: 100px;" + content;
|
222 | }
|
223 |
|
224 | return "@value: 200px;" + content;
|
225 | },
|
226 | },
|
227 | },
|
228 | ],
|
229 | },
|
230 | ],
|
231 | },
|
232 | };
|
233 | ```
|
234 |
|
235 | ##### `Async`
|
236 |
|
237 | ```js
|
238 | module.exports = {
|
239 | module: {
|
240 | rules: [
|
241 | {
|
242 | test: /\.less$/i,
|
243 | use: [
|
244 | "style-loader",
|
245 | "css-loader",
|
246 | {
|
247 | loader: "less-loader",
|
248 | options: {
|
249 | additionalData: async (content, loaderContext) => {
|
250 | // More information about available properties https://webpack.js.org/api/loaders/
|
251 | const { resourcePath, rootContext } = loaderContext;
|
252 | const relativePath = path.relative(rootContext, resourcePath);
|
253 |
|
254 | if (relativePath === "styles/foo.less") {
|
255 | return "@value: 100px;" + content;
|
256 | }
|
257 |
|
258 | return "@value: 200px;" + content;
|
259 | },
|
260 | },
|
261 | },
|
262 | ],
|
263 | },
|
264 | ],
|
265 | },
|
266 | };
|
267 | ```
|
268 |
|
269 | ### `sourceMap`
|
270 |
|
271 | Type:
|
272 |
|
273 | ```ts
|
274 | type sourceMap = boolean;
|
275 | ```
|
276 |
|
277 | Default: depends on the `compiler.devtool` value
|
278 |
|
279 | By default generation of source maps depends on the [`devtool`](https://webpack.js.org/configuration/devtool/) option. All values enable source map generation except `eval` and `false` value.
|
280 |
|
281 | **webpack.config.js**
|
282 |
|
283 | ```js
|
284 | module.exports = {
|
285 | module: {
|
286 | rules: [
|
287 | {
|
288 | test: /\.less$/i,
|
289 | use: [
|
290 | "style-loader",
|
291 | {
|
292 | loader: "css-loader",
|
293 | options: {
|
294 | sourceMap: true,
|
295 | },
|
296 | },
|
297 | {
|
298 | loader: "less-loader",
|
299 | options: {
|
300 | sourceMap: true,
|
301 | },
|
302 | },
|
303 | ],
|
304 | },
|
305 | ],
|
306 | },
|
307 | };
|
308 | ```
|
309 |
|
310 | ### `webpackImporter`
|
311 |
|
312 | Type:
|
313 |
|
314 | ```ts
|
315 | type webpackImporter = boolean;
|
316 | ```
|
317 |
|
318 | Default: `true`
|
319 |
|
320 | Enables/Disables the default `webpack` importer.
|
321 |
|
322 | This can improve performance in some cases. Use it with caution because aliases and `@import` from [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules) will not work.
|
323 |
|
324 | **webpack.config.js**
|
325 |
|
326 | ```js
|
327 | module.exports = {
|
328 | module: {
|
329 | rules: [
|
330 | {
|
331 | test: /\.less$/i,
|
332 | use: [
|
333 | "style-loader",
|
334 | "css-loader",
|
335 | {
|
336 | loader: "less-loader",
|
337 | options: {
|
338 | webpackImporter: false,
|
339 | },
|
340 | },
|
341 | ],
|
342 | },
|
343 | ],
|
344 | },
|
345 | };
|
346 | ```
|
347 |
|
348 | ### `implementation`
|
349 |
|
350 | Type:
|
351 |
|
352 | ```ts
|
353 | type implementation = object | string;
|
354 | ```
|
355 |
|
356 | > less-loader compatible with Less 3 and 4 versions
|
357 |
|
358 | The special `implementation` option determines which implementation of Less to use. Overrides the locally installed `peerDependency` version of `less`.
|
359 |
|
360 | **This option is only really useful for downstream tooling authors to ease the Less 3-to-4 transition.**
|
361 |
|
362 | #### `object`
|
363 |
|
364 | **webpack.config.js**
|
365 |
|
366 | ```js
|
367 | module.exports = {
|
368 | module: {
|
369 | rules: [
|
370 | {
|
371 | test: /\.less$/i,
|
372 | use: [
|
373 | "style-loader",
|
374 | "css-loader",
|
375 | {
|
376 | loader: "less-loader",
|
377 | options: {
|
378 | implementation: require("less"),
|
379 | },
|
380 | },
|
381 | ],
|
382 | },
|
383 | ],
|
384 | },
|
385 | };
|
386 | ```
|
387 |
|
388 | #### `string`
|
389 |
|
390 | **webpack.config.js**
|
391 |
|
392 | ```js
|
393 | module.exports = {
|
394 | module: {
|
395 | rules: [
|
396 | {
|
397 | test: /\.less$/i,
|
398 | use: [
|
399 | "style-loader",
|
400 | "css-loader",
|
401 | {
|
402 | loader: "less-loader",
|
403 | options: {
|
404 | implementation: require.resolve("less"),
|
405 | },
|
406 | },
|
407 | ],
|
408 | },
|
409 | ],
|
410 | },
|
411 | };
|
412 | ```
|
413 |
|
414 | ## Examples
|
415 |
|
416 | ### Normal usage
|
417 |
|
418 | Chain the `less-loader` with the [`css-loader`](https://github.com/webpack-contrib/css-loader) and the [`style-loader`](https://github.com/webpack-contrib/style-loader) to immediately apply all styles to the DOM.
|
419 |
|
420 | **webpack.config.js**
|
421 |
|
422 | ```js
|
423 | module.exports = {
|
424 | module: {
|
425 | rules: [
|
426 | {
|
427 | test: /\.less$/i,
|
428 | use: [
|
429 | {
|
430 | loader: "style-loader", // creates style nodes from JS strings
|
431 | },
|
432 | {
|
433 | loader: "css-loader", // translates CSS into CommonJS
|
434 | },
|
435 | {
|
436 | loader: "less-loader", // compiles Less to CSS
|
437 | },
|
438 | ],
|
439 | },
|
440 | ],
|
441 | },
|
442 | };
|
443 | ```
|
444 |
|
445 | Unfortunately, Less doesn't map all options 1-by-1 to camelCase. When in doubt, [check their executable](https://github.com/less/less.js/blob/3.x/bin/lessc) and search for the dash-case option.
|
446 |
|
447 | ### Source maps
|
448 |
|
449 | To enable sourcemaps for CSS, you'll need to pass the `sourceMap` property in the loader's options. If this is not passed, the loader will respect the setting for webpack source maps, set in `devtool`.
|
450 |
|
451 | **webpack.config.js**
|
452 |
|
453 | ```js
|
454 | module.exports = {
|
455 | devtool: "source-map", // any "source-map"-like devtool is possible
|
456 | module: {
|
457 | rules: [
|
458 | {
|
459 | test: /\.less$/i,
|
460 | use: [
|
461 | "style-loader",
|
462 | {
|
463 | loader: "css-loader",
|
464 | options: {
|
465 | sourceMap: true,
|
466 | },
|
467 | },
|
468 | {
|
469 | loader: "less-loader",
|
470 | options: {
|
471 | sourceMap: true,
|
472 | },
|
473 | },
|
474 | ],
|
475 | },
|
476 | ],
|
477 | },
|
478 | };
|
479 | ```
|
480 |
|
481 | If you want to edit the original Less files inside Chrome, [there's a good blog post](https://medium.com/@toolmantim/getting-started-with-css-sourcemaps-and-in-browser-sass-editing-b4daab987fb0). The blog post is about Sass but it also works for Less.
|
482 |
|
483 | ### In production
|
484 |
|
485 | Usually, it's recommended to extract the style sheets into a dedicated file in production using the [MiniCssExtractPlugin](https://github.com/webpack-contrib/mini-css-extract-plugin). This way your styles are not dependent on JavaScript.
|
486 |
|
487 | ### Imports
|
488 |
|
489 | First we try to use built-in `less` resolve logic, then `webpack` resolve logic.
|
490 |
|
491 | #### Webpack Resolver
|
492 |
|
493 | `webpack` provides an [advanced mechanism to resolve files](https://webpack.js.org/configuration/resolve/).
|
494 | `less-loader` applies a Less plugin that passes all queries to the webpack resolver if `less` could not resolve `@import`.
|
495 | Thus you can import your Less modules from `node_modules`.
|
496 |
|
497 | ```css
|
498 | @import "bootstrap/less/bootstrap";
|
499 | ```
|
500 |
|
501 | Using `~` is deprecated and can be removed from your code (**we recommend it**), but we still support it for historical reasons.
|
502 | Why you can removed it? The loader will first try to resolve `@import` as relative, if it cannot be resolved, the loader will try to resolve `@import` inside [`node_modules`](https://webpack.js.org/configuration/resolve/#resolvemodules).
|
503 |
|
504 | Default resolver options can be modified by [`resolve.byDependency`](https://webpack.js.org/configuration/resolve/#resolvebydependency):
|
505 |
|
506 | **webpack.config.js**
|
507 |
|
508 | ```js
|
509 | module.exports = {
|
510 | devtool: "source-map", // any "source-map"-like devtool is possible
|
511 | module: {
|
512 | rules: [
|
513 | {
|
514 | test: /\.less$/i,
|
515 | use: ["style-loader", "css-loader", "less-loader"],
|
516 | },
|
517 | ],
|
518 | },
|
519 | resolve: {
|
520 | byDependency: {
|
521 | // More options can be found here https://webpack.js.org/configuration/resolve/
|
522 | less: {
|
523 | mainFiles: ["custom"],
|
524 | },
|
525 | },
|
526 | },
|
527 | };
|
528 | ```
|
529 |
|
530 | #### Less Resolver
|
531 |
|
532 | If you specify the `paths` option, modules will be searched in the given `paths`. This is `less` default behavior. `paths` should be an array with absolute paths:
|
533 |
|
534 | **webpack.config.js**
|
535 |
|
536 | ```js
|
537 | module.exports = {
|
538 | module: {
|
539 | rules: [
|
540 | {
|
541 | test: /\.less$/i,
|
542 | use: [
|
543 | {
|
544 | loader: "style-loader",
|
545 | },
|
546 | {
|
547 | loader: "css-loader",
|
548 | },
|
549 | {
|
550 | loader: "less-loader",
|
551 | options: {
|
552 | lessOptions: {
|
553 | paths: [path.resolve(__dirname, "node_modules")],
|
554 | },
|
555 | },
|
556 | },
|
557 | ],
|
558 | },
|
559 | ],
|
560 | },
|
561 | };
|
562 | ```
|
563 |
|
564 | ### Plugins
|
565 |
|
566 | In order to use [plugins](http://lesscss.org/usage/#plugins), simply set the `plugins` option like this:
|
567 |
|
568 | **webpack.config.js**
|
569 |
|
570 | ```js
|
571 | const CleanCSSPlugin = require('less-plugin-clean-css');
|
572 |
|
573 | module.exports = {
|
574 | ...
|
575 | {
|
576 | loader: 'less-loader',
|
577 | options: {
|
578 | lessOptions: {
|
579 | plugins: [
|
580 | new CleanCSSPlugin({ advanced: true }),
|
581 | ],
|
582 | },
|
583 | },
|
584 | },
|
585 | ...
|
586 | };
|
587 | ```
|
588 |
|
589 | > **Note**
|
590 | >
|
591 | > Access to the [loader context](https://webpack.js.org/api/loaders/#the-loader-context) inside the custom plugin can be done using the `pluginManager.webpackLoaderContext` property.
|
592 |
|
593 | ```js
|
594 | module.exports = {
|
595 | install: function (less, pluginManager, functions) {
|
596 | functions.add("pi", function () {
|
597 | // Loader context is available in `pluginManager.webpackLoaderContext`
|
598 |
|
599 | return Math.PI;
|
600 | });
|
601 | },
|
602 | };
|
603 | ```
|
604 |
|
605 | ### Extracting style sheets
|
606 |
|
607 | Bundling CSS with webpack has some nice advantages like referencing images and fonts with hashed urls or [hot module replacement](https://webpack.js.org/concepts/hot-module-replacement/) in development. In production, on the other hand, it's not a good idea to apply your style sheets depending on JS execution. Rendering may be delayed or even a [FOUC](https://en.wikipedia.org/wiki/Flash_of_unstyled_content) might be visible. Thus it's often still better to have them as separate files in your final production build.
|
608 |
|
609 | There are two possibilities to extract a style sheet from the bundle:
|
610 |
|
611 | - [`extract-loader`](https://github.com/peerigon/extract-loader) (simpler, but specialized on the css-loader's output)
|
612 | - [`MiniCssExtractPlugin`](https://github.com/webpack-contrib/mini-css-extract-plugin) (more complex, but works in all use-cases)
|
613 |
|
614 | ### CSS modules gotcha
|
615 |
|
616 | There is a known problem with Less and [CSS modules](https://github.com/css-modules/css-modules) regarding relative file paths in `url(...)` statements. [See this issue for an explanation](https://github.com/webpack-contrib/less-loader/issues/109#issuecomment-253797335).
|
617 |
|
618 | ## Contributing
|
619 |
|
620 | Please take a moment to read our contributing guidelines if you haven't yet done so.
|
621 |
|
622 | [CONTRIBUTING](./.github/CONTRIBUTING.md)
|
623 |
|
624 | ## License
|
625 |
|
626 | [MIT](./LICENSE)
|
627 |
|
628 | [npm]: https://img.shields.io/npm/v/less-loader.svg
|
629 | [npm-url]: https://npmjs.com/package/less-loader
|
630 | [node]: https://img.shields.io/node/v/less-loader.svg
|
631 | [node-url]: https://nodejs.org
|
632 | [tests]: https://github.com/webpack-contrib/less-loader/workflows/less-loader/badge.svg
|
633 | [tests-url]: https://github.com/webpack-contrib/less-loader/actions
|
634 | [cover]: https://codecov.io/gh/webpack-contrib/less-loader/branch/master/graph/badge.svg
|
635 | [cover-url]: https://codecov.io/gh/webpack-contrib/less-loader
|
636 | [discussion]: https://img.shields.io/github/discussions/webpack/webpack
|
637 | [discussion-url]: https://github.com/webpack/webpack/discussions
|
638 | [size]: https://packagephobia.now.sh/badge?p=less-loader
|
639 | [size-url]: https://packagephobia.now.sh/result?p=less-loader
|