Skip to content

Instantly share code, notes, and snippets.

@denistex
Created May 4, 2020 16:33
Show Gist options
  • Save denistex/689cc39ca68cf329eb9c32c155187ef6 to your computer and use it in GitHub Desktop.
Save denistex/689cc39ca68cf329eb9c32c155187ef6 to your computer and use it in GitHub Desktop.
Rescript to connect antd-scss-theme-plugin correctly
'use strict'
const { getPaths, edit } = require('@rescripts/utilities')
const loaderUtils = require('loader-utils')
const path = require('path')
const paths = require('react-scripts/config/paths')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const AntdScssThemePlugin = require('@atbtech/antd-scss-theme-plugin')
const postcssNormalize = require('postcss-normalize')
const isEnvDevelopment = process.env.NODE_ENV === 'development'
const isEnvProduction = process.env.NODE_ENV === 'production'
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'
const regexes = {
css: /\.css$/,
cssModule: /\.module\.css$/,
less: /\.less$/,
lessModule: /\.module\.less$/,
sass: /\.(scss|sass)$/,
sassModule: /\.module\.(scss|sass)$/
}
const newStyleLoaders = [
{
test: regexes.css,
exclude: regexes.cssModule,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
}),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: regexes.cssModule,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
getLocalIdent: getCSSModuleLocalIdent
}
})
},
// Opt-in support for LeSS (using .less extension).
// By default we support LESS Modules with the
// extension .module.less
{
test: regexes.less,
exclude: regexes.lessModule,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
},
'less-loader',
{
lessOptions: {
javascriptEnabled: true,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
}
}
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true
},
// Adds support for CSS Modules, but using LESS
// using the extension .module.less
{
test: regexes.lessModule,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
getLocalIdent: getCSSModuleLocalIdent
}
},
'less-loader',
{
lessOptions: {
javascriptEnabled: true,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
}
}
)
},
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: regexes.sass,
exclude: regexes.sassModule,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
},
'sass-loader'
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: regexes.sassModule,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
getLocalIdent: getCSSModuleLocalIdent
}
},
'sass-loader'
)
}
]
const isStyleLoaders = x => x && Array.isArray(x.oneOf)
function withLessLoader (config) {
return edit(
section => {
const res = Object.values(regexes).map(x => x.toString())
const filtered =
section.oneOf.filter(x => !x.test || !res.includes(x.test.toString()))
const jsLoaders = filtered.slice(0, filtered.length - 1)
const fileLoader = filtered[filtered.length - 1]
section.oneOf = [].concat(jsLoaders, newStyleLoaders, fileLoader)
return section
},
getPaths(isStyleLoaders, config),
config
)
}
// https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/config/webpack.config.js
// Modifications:
// 1. Wrap the preProcessor with AntdScssThemePlugin.
// 2. Remove resolving of preProcessor (it should be overriden by
// AntdScssThemePlugin.themify).
// 3. Add preProcessorOptions.
function getStyleLoaders (cssOptions, preProcessor, preProcessorOptions) { // [3]
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
// css is located in `static/css`, use '../../' to locate index.html folder
// in production `paths.publicUrlOrPath` can be a relative path
options: paths.publicUrlOrPath.startsWith('.')
? { publicPath: '../../' }
: {}
},
{
loader: require.resolve('css-loader'),
options: cssOptions
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
postcssNormalize()
],
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
}
}
].filter(Boolean)
if (preProcessor) {
loaders.push(
{
loader: require.resolve('resolve-url-loader'),
options: {
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment
}
},
AntdScssThemePlugin.themify({ // [1]
loader: preProcessor, // [2]
options: Object.assign({ sourceMap: true }, preProcessorOptions) // [3]
})
)
}
return loaders
}
// https://github.com/facebook/create-react-app/blob/master/packages/react-dev-utils/getCSSModuleLocalIdent.js
// Modifications:
// 1. Add the 'less' option.
function getCSSModuleLocalIdent (
context,
localIdentName,
localName,
options
) {
// Use the filename or folder name, based on some uses the index.js / index.module.(css|scss|sass) project style
const fileNameOrFolder = context.resourcePath.match(
/index\.module\.(css|less|scss|sass)$/ // [1]
)
? '[folder]'
: '[name]'
// Create a hash based on a the file location and class name. Will be unique across a project, and close to globally unique.
const hash = loaderUtils.getHashDigest(
path.posix.relative(context.rootContext, context.resourcePath) + localName,
'md5',
'base64',
5
)
// Use loaderUtils to find the file or folder name
const className = loaderUtils.interpolateName(
context,
fileNameOrFolder + '_' + localName + '__' + hash,
options
)
// remove the .module that appears in every classname when based on the file.
return className.replace('.module_', '_')
}
module.exports = [
{
webpack: config => {
config.resolve.extensions = [...config.resolve.extensions, '.less']
const themePath = path.join(__dirname, '..', 'src', 'theme.scss')
config.plugins = [...config.plugins, new AntdScssThemePlugin(themePath)]
const result = withLessLoader(config)
return result
}
},
[
'use-babel-config',
{
presets: ['react-app'],
plugins: [
[
'import',
{
libraryName: 'antd',
style: true
}
]
]
}
]
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment