Skip to content

Commit 4f28957

Browse files
fix: avoid losing use during incremental build (#425)
1 parent 08cbc1a commit 4f28957

File tree

4 files changed

+109
-30
lines changed

4 files changed

+109
-30
lines changed

src/index.js

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,15 @@ export default async function stylusLoader(source) {
4343
: `${options.additionalData}\n${data}`;
4444
}
4545

46-
const stylusOptions = getStylusOptions(this, options);
46+
let stylusOptions;
47+
48+
try {
49+
stylusOptions = getStylusOptions(this, options);
50+
} catch (err) {
51+
callback(err);
52+
return;
53+
}
54+
4755
const styl = implementation(data, stylusOptions);
4856

4957
// include regular CSS on @import
@@ -79,34 +87,6 @@ export default async function stylusLoader(source) {
7987
);
8088
}
8189

82-
if (
83-
typeof stylusOptions.use !== "undefined" &&
84-
stylusOptions.use.length > 0
85-
) {
86-
let { length } = stylusOptions.use;
87-
88-
// eslint-disable-next-line no-plusplus
89-
while (length--) {
90-
let [item] = stylusOptions.use.splice(length, 1);
91-
if (typeof item === "string") {
92-
try {
93-
const resolved = require.resolve(item);
94-
95-
// eslint-disable-next-line import/no-dynamic-require, global-require
96-
item = require(resolved)(stylusOptions);
97-
} catch (error) {
98-
callback(
99-
`Failed to load "${item}" Stylus plugin. Are you sure it's installed?\n${error}`,
100-
);
101-
102-
return;
103-
}
104-
}
105-
106-
styl.use(item);
107-
}
108-
}
109-
11090
if (typeof stylusOptions.import !== "undefined") {
11191
for (const imported of stylusOptions.import) {
11292
styl.import(imported);

src/utils.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,29 @@ function getStylusOptions(loaderContext, loaderOptions) {
3636
_imports: [],
3737
};
3838

39+
if (typeof stylusOptions.use !== "undefined") {
40+
stylusOptions.use = (
41+
Array.isArray(stylusOptions.use) ? stylusOptions.use : [stylusOptions.use]
42+
).map((item) => {
43+
if (typeof item === "string") {
44+
try {
45+
const resolved = require.resolve(item);
46+
47+
loaderContext.addBuildDependency(resolved);
48+
49+
// eslint-disable-next-line import/no-dynamic-require, global-require
50+
return require(resolved)(stylusOptions);
51+
} catch (error) {
52+
throw new Error(
53+
`Failed to load "${item}" Stylus plugin. Are you sure it's installed?\n${error}`,
54+
);
55+
}
56+
}
57+
58+
return item;
59+
});
60+
}
61+
3962
// https://github.com/stylus/stylus/issues/2119
4063
stylusOptions.resolveURL =
4164
typeof stylusOptions.resolveURL === "boolean" && !stylusOptions.resolveURL

test/__snapshots__/loader.test.js.snap

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -708,7 +708,7 @@ exports[`loader should emit error when unresolved import: warnings 1`] = `[]`;
708708
exports[`loader should emit warning when use unresolved plugin: errors 1`] = `
709709
[
710710
"ModuleBuildError: Module build failed (from \`replaced original path\`):
711-
NonErrorEmittedError: (Emitted value instead of an instance of Error) Failed to load "unresolved" Stylus plugin. Are you sure it's installed?",
711+
Error: Failed to load "unresolved" Stylus plugin. Are you sure it's installed?",
712712
]
713713
`;
714714

@@ -927,6 +927,17 @@ exports[`loader should work "prefix" option: errors 1`] = `[]`;
927927

928928
exports[`loader should work "prefix" option: warnings 1`] = `[]`;
929929

930+
exports[`loader should work "use" option #1: css 1`] = `
931+
"body {
932+
width: 100%;
933+
}
934+
"
935+
`;
936+
937+
exports[`loader should work "use" option #1: errors 1`] = `[]`;
938+
939+
exports[`loader should work "use" option #1: warnings 1`] = `[]`;
940+
930941
exports[`loader should work "use" option as Array<string>: css 1`] = `
931942
"body {
932943
font: 12px Helvetica, Arial, sans-serif;
@@ -943,6 +954,22 @@ exports[`loader should work "use" option as Array<string>: errors 1`] = `[]`;
943954
944955
exports[`loader should work "use" option as Array<string>: warnings 1`] = `[]`;
945956
957+
exports[`loader should work "use" option as string: css 1`] = `
958+
"body {
959+
font: 12px Helvetica, Arial, sans-serif;
960+
}
961+
a.button {
962+
-webkit-border-radius: 5px;
963+
-moz-border-radius: 5px;
964+
border-radius: 5px;
965+
}
966+
"
967+
`;
968+
969+
exports[`loader should work "use" option as string: errors 1`] = `[]`;
970+
971+
exports[`loader should work "use" option as string: warnings 1`] = `[]`;
972+
946973
exports[`loader should work "use" option: css 1`] = `
947974
"body {
948975
width: 100%;

test/loader.test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,55 @@ describe("loader", () => {
570570
expect(getErrors(stats)).toMatchSnapshot("errors");
571571
});
572572

573+
it('should work "use" option #1', async () => {
574+
function plugin() {
575+
return (style) => {
576+
style.define("add", (a, b) => a.operate("+", b));
577+
};
578+
}
579+
580+
const testId = "./webpack.config-plugin.styl";
581+
const compiler = getCompiler(testId, {
582+
stylusOptions: {
583+
use: plugin(),
584+
},
585+
});
586+
const stats = await compile(compiler);
587+
const codeFromBundle = getCodeFromBundle(stats, compiler);
588+
const codeFromStylus = await getCodeFromStylus(testId, {
589+
stylusOptions: {
590+
use: plugin(),
591+
},
592+
});
593+
594+
expect(codeFromBundle.css).toBe(codeFromStylus.css);
595+
expect(codeFromBundle.css).toMatchSnapshot("css");
596+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
597+
expect(getErrors(stats)).toMatchSnapshot("errors");
598+
});
599+
600+
it('should work "use" option as string', async () => {
601+
const testId = "./basic.styl";
602+
const compiler = getCompiler(testId, {
603+
stylusOptions: {
604+
use: "nib",
605+
},
606+
});
607+
const stats = await compile(compiler);
608+
const codeFromBundle = getCodeFromBundle(stats, compiler);
609+
const codeFromStylus = await getCodeFromStylus(testId, {
610+
stylusOptions: {
611+
// eslint-disable-next-line global-require
612+
use: require("nib")(),
613+
},
614+
});
615+
616+
expect(codeFromBundle.css).toBe(codeFromStylus.css);
617+
expect(codeFromBundle.css).toMatchSnapshot("css");
618+
expect(getWarnings(stats)).toMatchSnapshot("warnings");
619+
expect(getErrors(stats)).toMatchSnapshot("errors");
620+
});
621+
573622
it('should work "use" option as Array<string>', async () => {
574623
const testId = "./basic.styl";
575624
const compiler = getCompiler(testId, {

0 commit comments

Comments
 (0)