Skip to content

Commit

Permalink
fix: avoid losing use during incremental build (#425)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait committed Sep 18, 2024
1 parent 08cbc1a commit 4f28957
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 30 deletions.
38 changes: 9 additions & 29 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,15 @@ export default async function stylusLoader(source) {
: `${options.additionalData}\n${data}`;
}

const stylusOptions = getStylusOptions(this, options);
let stylusOptions;

try {
stylusOptions = getStylusOptions(this, options);
} catch (err) {
callback(err);
return;
}

const styl = implementation(data, stylusOptions);

// include regular CSS on @import
Expand Down Expand Up @@ -79,34 +87,6 @@ export default async function stylusLoader(source) {
);
}

if (
typeof stylusOptions.use !== "undefined" &&
stylusOptions.use.length > 0
) {
let { length } = stylusOptions.use;

// eslint-disable-next-line no-plusplus
while (length--) {
let [item] = stylusOptions.use.splice(length, 1);
if (typeof item === "string") {
try {
const resolved = require.resolve(item);

// eslint-disable-next-line import/no-dynamic-require, global-require
item = require(resolved)(stylusOptions);
} catch (error) {
callback(
`Failed to load "${item}" Stylus plugin. Are you sure it's installed?\n${error}`,
);

return;
}
}

styl.use(item);
}
}

if (typeof stylusOptions.import !== "undefined") {
for (const imported of stylusOptions.import) {
styl.import(imported);
Expand Down
23 changes: 23 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,29 @@ function getStylusOptions(loaderContext, loaderOptions) {
_imports: [],
};

if (typeof stylusOptions.use !== "undefined") {
stylusOptions.use = (
Array.isArray(stylusOptions.use) ? stylusOptions.use : [stylusOptions.use]
).map((item) => {
if (typeof item === "string") {
try {
const resolved = require.resolve(item);

loaderContext.addBuildDependency(resolved);

// eslint-disable-next-line import/no-dynamic-require, global-require
return require(resolved)(stylusOptions);
} catch (error) {
throw new Error(
`Failed to load "${item}" Stylus plugin. Are you sure it's installed?\n${error}`,
);
}
}

return item;
});
}

// https://github.com/stylus/stylus/issues/2119
stylusOptions.resolveURL =
typeof stylusOptions.resolveURL === "boolean" && !stylusOptions.resolveURL
Expand Down
29 changes: 28 additions & 1 deletion test/__snapshots__/loader.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -708,7 +708,7 @@ exports[`loader should emit error when unresolved import: warnings 1`] = `[]`;
exports[`loader should emit warning when use unresolved plugin: errors 1`] = `
[
"ModuleBuildError: Module build failed (from \`replaced original path\`):
NonErrorEmittedError: (Emitted value instead of an instance of Error) Failed to load "unresolved" Stylus plugin. Are you sure it's installed?",
Error: Failed to load "unresolved" Stylus plugin. Are you sure it's installed?",
]
`;

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

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

exports[`loader should work "use" option #1: css 1`] = `
"body {
width: 100%;
}
"
`;

exports[`loader should work "use" option #1: errors 1`] = `[]`;

exports[`loader should work "use" option #1: warnings 1`] = `[]`;

exports[`loader should work "use" option as Array<string>: css 1`] = `
"body {
font: 12px Helvetica, Arial, sans-serif;
Expand All @@ -943,6 +954,22 @@ exports[`loader should work "use" option as Array<string>: errors 1`] = `[]`;
exports[`loader should work "use" option as Array<string>: warnings 1`] = `[]`;
exports[`loader should work "use" option as string: css 1`] = `
"body {
font: 12px Helvetica, Arial, sans-serif;
}
a.button {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
"
`;
exports[`loader should work "use" option as string: errors 1`] = `[]`;
exports[`loader should work "use" option as string: warnings 1`] = `[]`;
exports[`loader should work "use" option: css 1`] = `
"body {
width: 100%;
Expand Down
49 changes: 49 additions & 0 deletions test/loader.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,55 @@ describe("loader", () => {
expect(getErrors(stats)).toMatchSnapshot("errors");
});

it('should work "use" option #1', async () => {
function plugin() {
return (style) => {
style.define("add", (a, b) => a.operate("+", b));
};
}

const testId = "./webpack.config-plugin.styl";
const compiler = getCompiler(testId, {
stylusOptions: {
use: plugin(),
},
});
const stats = await compile(compiler);
const codeFromBundle = getCodeFromBundle(stats, compiler);
const codeFromStylus = await getCodeFromStylus(testId, {
stylusOptions: {
use: plugin(),
},
});

expect(codeFromBundle.css).toBe(codeFromStylus.css);
expect(codeFromBundle.css).toMatchSnapshot("css");
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");
});

it('should work "use" option as string', async () => {
const testId = "./basic.styl";
const compiler = getCompiler(testId, {
stylusOptions: {
use: "nib",
},
});
const stats = await compile(compiler);
const codeFromBundle = getCodeFromBundle(stats, compiler);
const codeFromStylus = await getCodeFromStylus(testId, {
stylusOptions: {
// eslint-disable-next-line global-require
use: require("nib")(),
},
});

expect(codeFromBundle.css).toBe(codeFromStylus.css);
expect(codeFromBundle.css).toMatchSnapshot("css");
expect(getWarnings(stats)).toMatchSnapshot("warnings");
expect(getErrors(stats)).toMatchSnapshot("errors");
});

it('should work "use" option as Array<string>', async () => {
const testId = "./basic.styl";
const compiler = getCompiler(testId, {
Expand Down

0 comments on commit 4f28957

Please sign in to comment.