已经在知乎混着发了三篇文章了,就快要熟悉了 !。
前言: 今天是十月一号,没错就是国庆假期的第一天,本该今天在回家的路上,却在在公司码字整理博客。可伶没有候补到回家的票 。一直以为只要添加候补,最后 12306 都能给票,结果发现是我太天真了,被 12306 着实教训了一把,还好早上六点多买了明天的。真是可惜,我以为我会比我给我妈买的手机 先到家,还是我慢了一步 。
正文: 今天主要是写一个 npm 包,所以如果你还不回发布 npm 的话,请查看文章 如何发布一个 npm 依赖包 。最近没开发新的项目,忙着改一些 UAT 的 bug,所以有点时间去捣鼓项目框架的问题,然后最近我利用空闲点的时间,成功切入到另一个项目,把 scss
改成 less
,被做完变量的全局化,然后事了拂衣去,深藏功与名 。讲下思路,在我升级项目的时候:
- 使用了 gulp 来批处理文件,手动是不可能手动的。
- 使用 craco-plugin-style-resources-loader 来做 less 变量全局化
为什么我要执着,去做 less 变量全局化呢?
原因是,一般我们的项目为了风格统一,例如「字体 | 按钮」大小、颜色、等等,往往是按一套标准的设计的,样式管理我们又能细分为两种:
- 公共类名来管理:例如某些按钮除了字不一样,大小颜色等完全一样,这时候我们会把它的样式写成公共样式,采用公共类名来管理
- 全局变量来管理:网页的颜色、字体等部分统一的样式,可以采用全局变量来管理。
但是通过全局变量来管理,有个缺点就是每次使用全局变量必须手动 @import
,这当然是 CSS 作用域影响的,我们无法改变这一点,这可就有点难受了。
变量全局化的解决思路
在写 React 项目的时候,我向来都是遇事不决, Vue 哲学。Vue 肯定有解决方案,果然:vue-cli => 向预处理器 Loader 传递选项 哇塞,直接支持 ,天底下还有比 Vue 更好用的框架吗 , 无奈用的 React ♀️。
好歹有 Vue,作为参考,我们在 React 根据 Vue-cli 的 CSS 相关 自动化导入 篇里提到的 style-resources-loader 去研究。
一看介绍,哇咔咔这个东西就是我们想要的:
- share your variables, mixins, functions across all style files, so you don't need to @import them manually.
- override variables in style files provided by other libraries (e.g. ant-design) and customize your own theme.
而且 Vue 都给我们封装好了,vue-cli-plugin-style-resources-loader React 又默默留下了泪水 。
根据 style-resources-loader 的使用说明:
CSS processor resources loader for webpack.
需要配合 webpack
如果项目是手配的就好了,可惜我用的 React
是通过 craco
来配置 webpack
的,好不容易找到了 craco-style-resources-loader 可惜只支持 CSS
,看了这个库的灵感来源:
This is a craco plugin to add style-resources-loader with create-react-app version >= 2.
Inspired by: https://github.com/tilap/craco-sass-resources-loader
好嘛也支持 SCSS:craco-sass-resources-loader
结果死活找不到 less 版本,不过既然 craco-style-resources-loader 都能根据 craco-sass-resources-loader 来模仿实现,那我也试试呗,毕竟去看了源码还是挺简单的。
未解之谜
动手解决问题之前这里有个未解之谜。
在 Antd 在 create-react-app 中使用 => 自定义主题 教程里面讲:
引入 craco-less
来帮助加载 less
样式和修改变量,通过 less
的 modifyVars
提供给 less-loader
达到变量覆盖功能。这是用到了 less 的 modifyVars。
但是 [less option](http://lesscss.org/usage/#less-options)
还有一个 Global Variables
属性可以给 less
注入全局变量。我配置了,但是并不能使用,估计是 craco
的导致的。
modifyVars 和 Global Variables 的使用参考:使用webpack+vue+less开发,使用less-loader,配置全局less变量
动手解决问题
我们的思路是给 webpack 配置 style-resources-loader 插件,让项目支持 CSS 变量的全局化。 我 React 项目中用到的是 Antd 推荐的一个库 craco 来配置 webpack 的。所以我们现在要做的就是借助 craco 的 API 来重写 webpack,把 style-resources-loader 插件加上去。在动手之前需要了解前置知识:
去看看 craco-sass-resources-loader 的源码,如何重写 webpack 的。
了解
craco
重写webpack
的 overrideCracoConfig 函数使用。
虽然是英文写的,但是很简单。要想添加一个新插件,我们需要新建一个文件:例如 craco-plugin-log-craco-config.js
。然后在 craco 的配置文件 craco.config.js
里面使用。craco-plugin-log-craco-config.js
文件里面的函数 overrideCracoConfig 函数第一个形参是 webpack 的配置,第二个形参是在craco.config.js
使用插件传过来的一些参数。
好了,接下来我给我们要发布到 npm 的库起名:craco-plugin-style-resources-loader
借助 overrideWebpackConfig 函数配置 webpack 的 loader ,代码如下:
module.exports = {
overrideWebpackConfig: ({ webpackConfig, pluginOptions }) => {
/* ============== start 校验传进来的参数是否正确 =============== */
// Check webpack config
if (
!webpackConfig ||
!webpackConfig.module ||
!webpackConfig.module.rules ||
typeof webpackConfig.module.rules !== 'object'
) {
throw new Error('craco-sass-resources-loader error: no valid webpackConfig.module.rules');
};
// Check variable pluginOptions
if ( Object.prototype.toString.call(pluginOptions) !== '[object Object]' ) {
throw new Error('craco-sass-resources-loader error: variable pluginOptions should is an object');
};
// Check styleType property
const mapStyleType = [ 'stylus', 'css', 'scss', 'sass', 'less' ];
const styleType = pluginOptions.styleType;
if ( typeof styleType !== 'string' ) {
throw new Error('craco-sass-resources-loader error: variable styleType is not a string');
} else if (!mapStyleType.includes(styleType)) {
throw new Error('craco-sass-resources-loader error: The value of variable styleType can only be 「stylus | css | scss | sass | less」');
};
/* ============== end =============== */
/* ============== start 如果你熟悉 webpack 就知道我们此处是找到 loader 配置 oneOf 参数,加上 style-resources-loader 插件=============== */
// Add the loader rule where needed
const output = { ...webpackConfig };
Object.keys(output.module.rules).forEach((ruleKey, ruleIndex) => {
const rule = output.module.rules[ruleKey];
if (Object.prototype.hasOwnProperty.call(rule, 'oneOf')) {
rule.oneOf.forEach((oneOf, oneOfIndex) => {
if ( oneOf.test && oneOf.use ) {
let useCssProcessor = false;
switch ( styleType ) {
case 'scss':
case 'sass':
useCssProcessor = `${oneOf.test}`.includes('scss') || `${oneOf.test}`.includes('sass');
break;
case 'css':
useCssProcessor = `${oneOf.test}`.includes('css') || `${oneOf.test}`.includes('style');
break;
default:
useCssProcessor = `${oneOf.test}`.includes(styleType);
break;
};
if ( useCssProcessor ) {
const options = {};
// more option go link: https://www.npmjs.com/package/style-resources-loader#patterns
pluginOptions.patterns && (options.patterns = pluginOptions.patterns);
pluginOptions.injector && (options.injector = pluginOptions.injector);
pluginOptions.globOptions && (options.globOptions = pluginOptions.globOptions);
pluginOptions.resolveUrl && (options.resolveUrl = pluginOptions.resolveUrl);
output.module.rules[ruleIndex].oneOf[oneOfIndex].use.push({
loader: 'style-resources-loader',
options,
});
};
};
});
};
});
/* ============== end =============== */
return output;
}
};
上面给支持了 scss/sass/css/less
, 然后可以直接发布到 npm 上。
- 要想看源码在此 :github 源码
- npm 链接在此: craco-plugin-style-resources-loader
安装之后,使用也很简单,如果你只有一个文件可以在 craco.config.js
里面这么使用 :patterns 参数为字符串就行
const cracoPluginStyleResourcesLoader = require('craco-plugin-style-resources-loader');
const path = require('path');
module.exports = {
plugin: cracoLessResourcesLoader,
options: {
patterns: path.join(__dirname, 'src/less/common.less'),
/*
Please enter supported CSS processor type
1. if u use css processor,please type css string
2. if u use less processor,please type less string
3. if u use sass or scss processor,please type sass or scss string,Choose one of the two
4. if u use stylus processor,please type stylus string
*/
styleType: 'less'
}
};
如果有多个文件需要变量全局化 , patterns 参数为数组就行:
const cracoPluginStyleResourcesLoader = require('craco-plugin-style-resources-loader');
const path = require('path');
module.exports = {
plugin: cracoLessResourcesLoader,
options: {
patterns: [
path.join(__dirname, 'src/less/common.less'),
path.join(__dirname, 'src/less/global.less')
],
/*
Please enter supported CSS processor type
1. if u use css processor,please type css string
2. if u use less processor,please type less string
3. if u use sass or scss processor,please type sass or scss string,Choose one of the two
4. if u use stylus processor,please type stylus string
*/
styleType: 'less'
}
};
options 还有另外有些配置,其参数都来自 style-resources-loader
不知道 npm 下载的统计准不准,就发布了一天现在下载已经 158 了 。
完 ~~~
写作时间 Thursday, October 1, 2020 16:54:15