Skip to content

Commit aee8482

Browse files
refactor: drop webpack@4 (#402)
BREAKING CHANGE: minimum supported `webpack` version is `5`
1 parent a6c4e89 commit aee8482

21 files changed

+264
-175
lines changed

.github/workflows/nodejs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
matrix:
5757
os: [ubuntu-latest, windows-latest, macos-latest]
5858
node-version: [10.x, 12.x, 14.x]
59-
webpack-version: [4, latest]
59+
webpack-version: [latest]
6060

6161
runs-on: ${{ matrix.os }}
6262

package-lock.json

Lines changed: 125 additions & 111 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,10 @@
3939
],
4040
"peerDependencies": {
4141
"less": "^3.5.0 || ^4.0.0",
42-
"webpack": "^4.0.0 || ^5.0.0"
42+
"webpack": "^5.0.0"
4343
},
4444
"dependencies": {
45-
"klona": "^2.0.4",
46-
"loader-utils": "^2.0.0",
47-
"schema-utils": "^3.0.0"
45+
"klona": "^2.0.4"
4846
},
4947
"devDependencies": {
5048
"@babel/cli": "^7.12.10",
@@ -58,20 +56,20 @@
5856
"cross-env": "^7.0.3",
5957
"del": "^6.0.0",
6058
"del-cli": "^3.0.1",
61-
"eslint": "^7.18.0",
59+
"eslint": "^7.19.0",
6260
"eslint-config-prettier": "^7.2.0",
6361
"eslint-plugin-import": "^2.22.1",
6462
"eslint-plugin-prettier": "^3.3.0",
6563
"husky": "^4.3.8",
6664
"jest": "^26.6.3",
67-
"less": "^4.1.0",
65+
"less": "^4.1.1",
6866
"lint-staged": "^10.5.3",
6967
"memfs": "^3.2.0",
7068
"npm-run-all": "^4.1.5",
7169
"prettier": "^2.2.1",
7270
"standard-version": "^9.1.0",
7371
"strip-ansi": "^6.0.0",
74-
"webpack": "^5.16.0"
72+
"webpack": "^5.19.0"
7573
},
7674
"keywords": [
7775
"webpack",

src/index.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,13 @@
11
import path from "path";
22

33
import less from "less";
4-
import { getOptions } from "loader-utils";
5-
import { validate } from "schema-utils";
64

75
import schema from "./options.json";
86
import { getLessOptions, isUnsupportedUrl, normalizeSourceMap } from "./utils";
97
import LessError from "./LessError";
108

119
async function lessLoader(source) {
12-
const options = getOptions(this);
13-
14-
validate(schema, options, {
15-
name: "Less Loader",
16-
baseDataPath: "options",
17-
});
18-
10+
const options = this.getOptions(schema);
1911
const callback = this.async();
2012
const lessOptions = getLessOptions(this, options);
2113
const useSourceMap =

src/options.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
2+
"title": "Less Loader options",
23
"type": "object",
34
"properties": {
45
"lessOptions": {

src/utils.js

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ import path from "path";
33
import less from "less";
44
import { klona } from "klona/full";
55

6-
import { urlToRequest } from "loader-utils";
7-
86
/* eslint-disable class-methods-use-this */
97
const trailingSlash = /[/\\]$/;
108

@@ -16,6 +14,16 @@ const IS_SPECIAL_MODULE_IMPORT = /^~[^/]+$/;
1614
// `[drive_letter]:\` + `\\[server]\[sharename]\`
1715
const IS_NATIVE_WIN32_PATH = /^[a-z]:[/\\]|^\\\\/i;
1816

17+
// Examples:
18+
// - ~package
19+
// - ~package/
20+
// - ~@org
21+
// - ~@org/
22+
// - ~@org/package
23+
// - ~@org/package/
24+
const IS_MODULE_IMPORT = /^~([^/]+|[^/]+\/|@[^/]+[/][^/]+|@[^/]+\/?|@[^/]+[/][^/]+\/)$/;
25+
const MODULE_REQUEST_REGEX = /^[^?]*~/;
26+
1927
/**
2028
* Creates a Less plugin that uses webpack's resolving engine that is provided by the loaderContext.
2129
*
@@ -28,6 +36,7 @@ function createWebpackLessPlugin(loaderContext) {
2836
mainFields: ["less", "style", "main", "..."],
2937
mainFiles: ["index", "..."],
3038
extensions: [".less", ".css"],
39+
preferRelative: true,
3140
});
3241

3342
class WebpackFileManager extends less.FileManager {
@@ -56,31 +65,40 @@ function createWebpackLessPlugin(loaderContext) {
5665
// Less is giving us trailing slashes, but the context should have no trailing slash
5766
const context = currentDirectory.replace(trailingSlash, "");
5867

59-
const request = urlToRequest(
60-
filename,
61-
// eslint-disable-next-line no-undefined
62-
filename.charAt(0) === "/" ? loaderContext.rootContext : undefined
63-
);
68+
let request = filename;
69+
70+
// A `~` makes the url an module
71+
if (MODULE_REQUEST_REGEX.test(filename)) {
72+
request = request.replace(MODULE_REQUEST_REGEX, "");
73+
}
74+
75+
if (IS_MODULE_IMPORT.test(filename)) {
76+
request = request[request.length - 1] === "/" ? request : `${request}/`;
77+
}
6478

6579
return this.resolveRequests(context, [...new Set([request, filename])]);
6680
}
6781

68-
resolveRequests(context, possibleRequests) {
82+
async resolveRequests(context, possibleRequests) {
6983
if (possibleRequests.length === 0) {
7084
return Promise.reject();
7185
}
7286

73-
return resolve(context, possibleRequests[0])
74-
.then((result) => result)
75-
.catch((error) => {
76-
const [, ...tailPossibleRequests] = possibleRequests;
87+
let result;
7788

78-
if (tailPossibleRequests.length === 0) {
79-
throw error;
80-
}
89+
try {
90+
result = await resolve(context, possibleRequests[0]);
91+
} catch (error) {
92+
const [, ...tailPossibleRequests] = possibleRequests;
93+
94+
if (tailPossibleRequests.length === 0) {
95+
throw error;
96+
}
8197

82-
return this.resolveRequests(context, tailPossibleRequests);
83-
});
98+
result = await this.resolveRequests(context, tailPossibleRequests);
99+
}
100+
101+
return result;
84102
}
85103

86104
async loadFile(filename, ...args) {

test/__snapshots__/loader.test.js.snap

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ body {
208208
background: url(assets/resources/circle.svg);
209209
}
210210
.abs {
211-
background: url(~assets/resources/circle.svg);
211+
background: url(assets/resources/circle.svg);
212212
}
213213
"
214214
`;
@@ -228,6 +228,20 @@ exports[`loader should not try to resolve CSS imports with URLs: errors 1`] = `A
228228
229229
exports[`loader should not try to resolve CSS imports with URLs: warnings 1`] = `Array []`;
230230
231+
exports[`loader should prefer-relativee imports correctly: css 1`] = `
232+
".prefer-relative-import {
233+
background: red;
234+
}
235+
.relative {
236+
color: coral;
237+
}
238+
"
239+
`;
240+
241+
exports[`loader should prefer-relativee imports correctly: errors 1`] = `Array []`;
242+
243+
exports[`loader should prefer-relativee imports correctly: warnings 1`] = `Array []`;
244+
231245
exports[`loader should provide a useful error message if the import could not be found: errors 1`] = `
232246
Array [
233247
"ModuleBuildError: Module build failed (from \`replaced original path\`):
@@ -354,7 +368,7 @@ body {
354368
background: url(assets/resources/circle.svg);
355369
}
356370
.abs {
357-
background: url(~assets/resources/circle.svg);
371+
background: url(assets/resources/circle.svg);
358372
}
359373
"
360374
`;
@@ -364,8 +378,8 @@ exports[`loader should resolve aliases in diffrent variants: errors 1`] = `Array
364378
exports[`loader should resolve aliases in diffrent variants: warnings 1`] = `Array []`;
365379
366380
exports[`loader should resolve all imports from node_modules using webpack's resolver: css 1`] = `
367-
"@import \\"~some/css.css\\";
368-
@import \\"~some/css.css\\";
381+
"@import \\"some/css.css\\";
382+
@import \\"some/css.css\\";
369383
#it-works {
370384
color: hotpink;
371385
}

test/__snapshots__/sourceMap-options.test.js.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Object {
2727
color: hotpink;
2828
}
2929
",
30-
"@import \\"~some/module\\";
30+
"@import \\"some/module\\";
3131
3232
#it-works:extend(.modules-dir-some-module) {
3333
margin: 10px;
@@ -67,7 +67,7 @@ Object {
6767
color: hotpink;
6868
}
6969
",
70-
"@import \\"~some/module\\";
70+
"@import \\"some/module\\";
7171
7272
#it-works:extend(.modules-dir-some-module) {
7373
margin: 10px;
@@ -107,7 +107,7 @@ Object {
107107
color: hotpink;
108108
}
109109
",
110-
"@import \\"~some/module\\";
110+
"@import \\"some/module\\";
111111
112112
#it-works:extend(.modules-dir-some-module) {
113113
margin: 10px;
@@ -147,7 +147,7 @@ Object {
147147
color: hotpink;
148148
}
149149
",
150-
"@import \\"~some/module\\";
150+
"@import \\"some/module\\";
151151
152152
#it-works:extend(.modules-dir-some-module) {
153153
margin: 10px;

test/__snapshots__/webpackImporter-options.test.js.snap

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ exports[`"webpackImporter" option should work when value is "false": errors 1`]
3737
exports[`"webpackImporter" option should work when value is "false": warnings 1`] = `Array []`;
3838

3939
exports[`"webpackImporter" option should work when value is "true": css 1`] = `
40-
"@import \\"~some/css.css\\";
41-
@import \\"~some/css.css\\";
40+
"@import \\"some/css.css\\";
41+
@import \\"some/css.css\\";
4242
#it-works {
4343
color: hotpink;
4444
}
@@ -57,8 +57,8 @@ exports[`"webpackImporter" option should work when value is "true": errors 1`] =
5757
exports[`"webpackImporter" option should work when value is "true": warnings 1`] = `Array []`;
5858

5959
exports[`"webpackImporter" option should work when value is not specify: css 1`] = `
60-
"@import \\"~some/css.css\\";
61-
@import \\"~some/css.css\\";
60+
"@import \\"some/css.css\\";
61+
@import \\"some/css.css\\";
6262
#it-works {
6363
color: hotpink;
6464
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
@import "not-existing";
1+
@import "~not-existing";

0 commit comments

Comments
 (0)