Skip to content

Commit e576240

Browse files
feat: added pluginManager.webpackLoaderContext, deprecated less.webpackLoaderContext, it fixed memory leak (#412)
1 parent 265179f commit e576240

File tree

7 files changed

+111
-16
lines changed

7 files changed

+111
-16
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ module.exports = {
3434
rules: [
3535
{
3636
test: /\.less$/i,
37-
loader: [ // compiles Less to CSS
37+
loader: [
38+
// compiles Less to CSS
3839
"style-loader",
3940
"css-loader",
4041
"less-loader",
@@ -529,13 +530,13 @@ module.exports = {
529530
};
530531
```
531532

532-
> ℹ️ Access to the [loader context](https://webpack.js.org/api/loaders/#the-loader-context) inside the custom plugin can be done using the `less.webpackLoaderContext` property.
533+
> ℹ️ 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.
533534
534535
```js
535536
module.exports = {
536537
install: function (less, pluginManager, functions) {
537538
functions.add("pi", function () {
538-
// Loader context is available in `less.webpackLoaderContext`
539+
// Loader context is available in `pluginManager.webpackLoaderContext`
539540

540541
return Math.PI;
541542
});

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ async function lessLoader(source) {
4444
return;
4545
}
4646

47+
if ("webpackLoaderContext" in less) {
48+
delete less.webpackLoaderContext;
49+
}
50+
4751
const { css, imports } = result;
4852

4953
imports.forEach((item) => {

src/utils.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import path from "path";
2+
import util from "util";
23

34
import less from "less";
45
import { klona } from "klona/full";
@@ -181,10 +182,26 @@ function getLessOptions(loaderContext, loaderOptions) {
181182
lessOptions.plugins.unshift(createWebpackLessPlugin(loaderContext));
182183
}
183184

185+
const webpackContextDeprecated = util.deprecate(
186+
(context) => context,
187+
"less.webpackLoaderContext is deprecated and will be removed in next major release. Instead use pluginManager.webpackLoaderContext (https://webpack.js.org/loaders/less-loader/#plugins)"
188+
);
189+
184190
lessOptions.plugins.unshift({
185-
install(lessProcessor) {
191+
install(lessProcessor, pluginManager) {
186192
// eslint-disable-next-line no-param-reassign
187-
lessProcessor.webpackLoaderContext = loaderContext;
193+
pluginManager.webpackLoaderContext = loaderContext;
194+
195+
// Todo remove in next major release
196+
if (typeof lessProcessor.webpackLoaderContext === "undefined") {
197+
Object.defineProperty(lessProcessor, "webpackLoaderContext", {
198+
configurable: true,
199+
200+
get() {
201+
return webpackContextDeprecated(loaderContext);
202+
},
203+
});
204+
}
188205
},
189206
});
190207

test/__snapshots__/loader.test.js.snap

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,26 +92,26 @@ exports[`loader should delegate resolving (LESS) imports with URLs to "less" pac
9292
font-family: 'Roboto';
9393
font-style: normal;
9494
font-weight: 300;
95-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
95+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
9696
}
9797
9898
@font-face {
9999
font-family: 'Roboto';
100100
font-style: normal;
101101
font-weight: 400;
102-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype');
102+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype');
103103
}
104104
@font-face {
105105
font-family: 'Roboto';
106106
font-style: normal;
107107
font-weight: 500;
108-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
108+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
109109
}
110110
@font-face {
111111
font-family: 'Roboto';
112112
font-style: normal;
113113
font-weight: 700;
114-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmWUlfBBc9.ttf) format('truetype');
114+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmWUlfBBc9.ttf) format('truetype');
115115
}
116116
"
117117
`;
@@ -157,25 +157,25 @@ exports[`loader should not add to dependencies imports with URLs: css 1`] = `
157157
font-family: 'Roboto';
158158
font-style: normal;
159159
font-weight: 300;
160-
src: url(http://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
160+
src: url(http://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
161161
}
162162
@font-face {
163163
font-family: 'Roboto';
164164
font-style: normal;
165165
font-weight: 300;
166-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
166+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmSU5fBBc9.ttf) format('truetype');
167167
}
168168
@font-face {
169169
font-family: 'Roboto';
170170
font-style: normal;
171171
font-weight: 400;
172-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype');
172+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOmCnqEu92Fr1Mu4mxP.ttf) format('truetype');
173173
}
174174
@font-face {
175175
font-family: 'Roboto';
176176
font-style: normal;
177177
font-weight: 500;
178-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
178+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
179179
}
180180
"
181181
`;
@@ -579,6 +579,17 @@ exports[`loader should work lessOptions.relativeUrls is true: errors 1`] = `Arra
579579
580580
exports[`loader should work lessOptions.relativeUrls is true: warnings 1`] = `Array []`;
581581
582+
exports[`loader should work loaderContext in less plugins 2: css 1`] = `
583+
".webpackLoaderContext {
584+
isDefined: true;
585+
}
586+
"
587+
`;
588+
589+
exports[`loader should work loaderContext in less plugins 2: errors 1`] = `Array []`;
590+
591+
exports[`loader should work loaderContext in less plugins 2: warnings 1`] = `Array []`;
592+
582593
exports[`loader should work loaderContext in less plugins: css 1`] = `
583594
".webpackLoaderContext {
584595
isDefined: true;
@@ -598,7 +609,7 @@ exports[`loader should work third-party plugins as fileLoader: css 1`] = `
598609
font-family: 'Roboto';
599610
font-style: normal;
600611
font-weight: 500;
601-
src: url(https://fonts.gstatic.com/s/roboto/v20/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
612+
src: url(https://fonts.gstatic.com/s/roboto/v27/KFOlCnqEu92Fr1MmEU9fBBc9.ttf) format('truetype');
602613
}
603614
.modules-dir-scope-module {
604615
color: hotpink;

test/fixtures/basic-plugins-2.less

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@plugin "plugin-2";
2+
3+
.webpackLoaderContext {
4+
isDefined: run();
5+
}

test/fixtures/plugin-2.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
registerPlugin({
2+
install: function(less, pluginManager, functions) {
3+
functions.add('run', function() {
4+
if (typeof pluginManager.webpackLoaderContext !== 'undefined') {
5+
return 'true';
6+
}
7+
8+
return 'false';
9+
});
10+
}
11+
})

test/loader.test.js

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ describe("loader", () => {
802802
constructor(less) {
803803
super();
804804

805-
if (typeof less.webpackLoaderContext !== "undefined") {
805+
if (typeof less.webpackLoaderContext.version !== "undefined") {
806806
contextInClass = true;
807807
}
808808
}
@@ -817,7 +817,7 @@ describe("loader", () => {
817817

818818
const customObjectPlugin = {
819819
install(less) {
820-
if (typeof less.webpackLoaderContext !== "undefined") {
820+
if (typeof less.webpackLoaderContext.version !== "undefined") {
821821
contextInObject = true;
822822
}
823823
},
@@ -839,6 +839,52 @@ describe("loader", () => {
839839
expect(getErrors(stats)).toMatchSnapshot("errors");
840840
});
841841

842+
it("should work loaderContext in less plugins 2", async () => {
843+
let contextInClass;
844+
let contextInObject;
845+
846+
// eslint-disable-next-line global-require
847+
class Plugin extends require("less").FileManager {
848+
constructor(less, pluginManager) {
849+
super();
850+
851+
if (typeof pluginManager.webpackLoaderContext !== "undefined") {
852+
contextInClass = true;
853+
}
854+
}
855+
}
856+
857+
class CustomClassPlugin {
858+
// eslint-disable-next-line class-methods-use-this
859+
install(less, pluginManager) {
860+
pluginManager.addFileManager(new Plugin(less, pluginManager));
861+
}
862+
}
863+
864+
const customObjectPlugin = {
865+
install(less, packageManager) {
866+
if (typeof packageManager.webpackLoaderContext !== "undefined") {
867+
contextInObject = true;
868+
}
869+
},
870+
};
871+
872+
const testId = "./basic-plugins-2.less";
873+
const compiler = getCompiler(testId, {
874+
lessOptions: {
875+
plugins: [new CustomClassPlugin(), customObjectPlugin],
876+
},
877+
});
878+
const stats = await compile(compiler);
879+
const codeFromBundle = getCodeFromBundle(stats, compiler);
880+
881+
expect(contextInClass).toBe(true);
882+
expect(contextInObject).toBe(true);
883+
expect(codeFromBundle.css).toMatchSnapshot("css");
884+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
885+
expect(getErrors(stats)).toMatchSnapshot("errors");
886+
});
887+
842888
// TODO bug on windows
843889
it.skip("should work with circular imports", async () => {
844890
const testId = "./circular.less";

0 commit comments

Comments
 (0)