Skip to content

Commit

Permalink
add addStylusLoader
Browse files Browse the repository at this point in the history
  • Loading branch information
billypon committed Mar 31, 2022
1 parent 7e97127 commit 086c1d1
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 0 deletions.
54 changes: 54 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ This file documents the functions exported by `customize-cra`.
- [setWebpackOptimizationSplitChunks](#setwebpackoptimizationsplitchunkstarget)
- [adjustWorkbox](#adjustworkboxfn)
- [addLessLoader](#addlessloaderloaderoptions)
- [addStylusLoader](#addstylusloaderloaderoptions)
- [addPostcssPlugins](#addpostcsspluginsplugins)
- [disableChunk](#disablechunk)
- [removeModuleScopePlugin](#removemodulescopeplugin)
Expand Down Expand Up @@ -414,6 +415,59 @@ declare module "*.module.less" {
}
```

### addStylusLoader(loaderOptions)

First, install `stylus` and `stylus-loader` packages:

```bash
yarn add --dev stylus stylus-loader
```

or:

```bash
npm i -D stylus stylus-loader
```

After it's done, call `addStylusLoader` in `override` like below:

```js
const { addStylusLoader } = require("customize-cra");

module.exports = override(addStylusLoader(loaderOptions));
```

`loaderOptions` is optional. If you have Stylus specific options, you can pass to it. For example:

```js
const { addStylusLoader } = require("customize-cra");

module.exports = override(
addStylusLoader({
stylusOptions: {}, // pass any options to stylus.
cssLoaderOptions: {}, // .styl file used css-loader option, not all CSS file.
cssModules: {
localIdentName: "[path][name]__[local]--[hash:base64:5]", // if you use CSS Modules, and custom `localIdentName`, default is '[local]--[hash:base64:5]'.
},
})
);
```

Check [stylus-loader document](https://github.com/webpack-contrib/stylus-loader#options) and [stylus document](https://stylus-lang.com/docs/js.html) for all available specific options you can use.

Once `stylus-loader` is enabled, you can import `.styl` file in your project.

`.module.styl` will use CSS Modules.

> if you use TypeScript (npm init react-app my-app --typescript) with CSS Modules, you should edit `react-app-env.d.ts`.
```typescript
declare module "*.module.styl" {
const classes: { [key: string]: string };
export default classes;
}
```

### addPostcssPlugins([plugins])

To add post-css plugins, you can use `addPostcssPlugins`.
Expand Down
122 changes: 122 additions & 0 deletions src/customizers/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,128 @@ export const addLessLoader = (loaderOptions = {}, customCssModules = {}) => conf
return config;
};

export const addStylusLoader = (loaderOptions = {}, customCssModules = {}) => config => {
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const postcssNormalize = require("postcss-normalize");

const cssLoaderOptions = loaderOptions.cssLoaderOptions || {};
delete loaderOptions.cssLoaderOptions;

const { localIdentName } = loaderOptions;
let cssModules = loaderOptions.cssModules || { localIdentName };

if (!cssModules.localIdentName) {
cssModules = customCssModules;
}

cssModules.localIdentName = cssModules.localIdentName || "[local]--[hash:base64:5]";

const stylusRegex = /\.styl$/;
const stylusModuleRegex = /\.module\.styl$/;

const webpackEnv = process.env.NODE_ENV;
const isEnvDevelopment = webpackEnv === "development";
const isEnvProduction = webpackEnv === "production";
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const publicPath = config.output.publicPath;
const shouldUseRelativeAssetPaths = publicPath === "./";

// copy from react-scripts
// https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/config/webpack.config.js#L93
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve("style-loader"),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
options: shouldUseRelativeAssetPaths ? { publicPath: "../../" } : {}
},
{
loader: require.resolve("css-loader"),
options: cssOptions
},
{
loader: require.resolve("postcss-loader"),
options: {
ident: "postcss",
plugins: () => [
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")({
autoprefixer: {
flexbox: "no-2009"
},
stage: 3
}),
postcssNormalize()
],
sourceMap: isEnvProduction && shouldUseSourceMap
}
}
].filter(Boolean);
if (preProcessor) {
loaders.push(
{
loader: require.resolve("resolve-url-loader"),
options: {
sourceMap: isEnvProduction && shouldUseSourceMap
}
},
{
loader: require.resolve(preProcessor),
// not the same as react-scripts
options: Object.assign(
{
sourceMap: true
},
loaderOptions
)
}
);
}
return loaders;
};

const loaders = config.module.rules.find(rule => Array.isArray(rule.oneOf))
.oneOf;

// Insert stylus-loader as the penultimate item of loaders (before file-loader)
loaders.splice(
loaders.length - 1,
0,
{
test: stylusRegex,
exclude: stylusModuleRegex,
use: getStyleLoaders(
Object.assign(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap
},
cssLoaderOptions
),
"stylus-loader"
)
},
{
test: stylusModuleRegex,
use: getStyleLoaders(
Object.assign(
{
importLoaders: 2,
sourceMap: isEnvProduction && shouldUseSourceMap
},
cssLoaderOptions,
{
modules: cssModules
}
),
"stylus-loader"
)
}
);

return config;
};

// to be used inside `overrideDevServer`, makes CRA watch all the folders
// included `node_modules`, useful when you are working with linked packages
// usage: `yarn start --watch-all`
Expand Down
2 changes: 2 additions & 0 deletions src/customizers/webpack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ test("adjustStyleLoaders find all style loaders and callback one by one", () =>

test("addLessLoader", () => {});

test("addStylusLoader", () => {});

test("watchAll removes the watchOptions from config if --watch-all passed", () => {
const watchOptions = { watch: true };
const inputConfig = { watchOptions };
Expand Down

0 comments on commit 086c1d1

Please sign in to comment.