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