由于项目在多地区进行发布,为了复用,主工程使用同一个,但是这样会带来一个问题,由于地区的设备分布不同,以及当地的字体选择不一样,从而导致了 global 中的一些熟悉无法复用,而且必须配置两套,那么如何来解决这个问题呢?

解决思路方法

由于项目中有一个非常基础的变量模块,暂且叫做 basic.scss ,然后在很多 scss 文件中都对该文件进行了引用,现在需要区分多个地区的基础配置,那么直接复制一份 basic.scss ,命名为 basic-[country].scss ,接下来就是要找到引用 basic.scss 的地方,然后在打包的时候将其替换为 basic-[country].scss 具体的国家或者地区就可以了。

那么这里就有问题是,怎么去找到这个文件,并且把引用关联找到,最后再替换,这种打包类的问题,当然 webpack 是首选。

webpack 选择

一开始思路是使用 webpack 来解决这个问题,那么到底是使用 loader 还是 plugin 呢?这里就需要去思考 loader 和 plugin 的区别。

这里引用一段说明:

作用不同

  • Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析非JavaScript文件的能力。
  • Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。

用法不同

  • Loader在module.rules中配置,也就是说作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
  • Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。

其实看到第一段就有答案了,webpack 原生是只能解析 js 文件,如果想要其他文件也打包的话,就需要使用到 loader ,所以这里我们选择使用 loader 来处理。

loader 插件选择

在 loader 插件中有一个插件一下进入了视野,那就是 string-replace-loader 我们看下他的一个例子:

module.exports = {// ...module: {rules: [{test: /fileInWhichJQueryIsUndefined\.js$/,loader: 'string-replace-loader',options: {search: '$',replace: 'window.jQuery',}}]}
}

用法也比较简单,使用正则查询需要处理的文件,然后使用 string-replace-loader 来处理,参数第一个 search 查询需要替换的字符串,第二个是需要替换成的字符串。

想到这里,那么直接修改为下面这个方式不就可以了吗?

module.exports = {// ...module: {rules: [{test: /[\s][\S]\.scss$/,loader: 'string-replace-loader',options: {search: 'basic.scss',replace: 'basic-[country].scss',}}]}
}

如果你自己写的 webpack 插件确实是这样就行了,但是由于我们使用的是 nextjs 框架,webpack 是自动生成的,因此我们需要看看 nextjs 如何应用。

nextjs 接入

nextjs 官方有提供 loader 或者 plugin 的写法,以下是官方的例子

module.exports = {webpack: (config, options) => {config.module.rules.push({test: /\.mdx/,use: [options.defaultLoaders.babel,{loader: '@mdx-js/loader',options: pluginOptions.options,},],})return config},
}

按照官网的例子,我们修改下,改为下面这种 scss 替换的方式

module.exports = {webpack: (config, options) => {config.module.rules.push({test: /[\s][\S]\.scss$/,use: [{loader: 'string-replace-loader',options: {search: 'basic.scss',replace: 'basic-[country].scss',}},],})return config},
}

修改完成以后,运行一下,你会发现解析其中会报错,而且要不就是说 css 解析不了,要不就是 less 解析不了,要不就是 js 问题等等。

看了下原因才发现,我们不能直接的 push 进去,而是应该在现有的 rules 的规则中增加该 loader ,那么接下来我们就来解决这个问题。

首先我们写一个方法,来添加这个 loader 规则:

 const addUserLoader = function(arr){if(!(arr instanceof Array)){return arr};arr.push({loader: 'string-replace-loader',options: {search: 'basic.scss',replace: 'basic-[country].scss',}});return arr;};

接下来,我们需要去遍历当前所有的 rule 规则,我们先把所有的 rule 规则都加上这个,看看有没有问题,代码如下。

webpackConfig.module.rules.forEach(rule => {if(rule.oneOf instanceof Array){let cssRules = [];rule.oneOf.forEach(cssRule => {if(cssRule.use instanceof Array){addUserLoader(cssRule.use);} else if(cssRule.use){addUserLoader([cssRule.use])}cssRules.push(cssRule);});rule.oneOf = cssRules;}newRules.push(rule);});webpackConfig.module.rules = newRules;return webpackConfig;

代码逻辑是比较简单的,遍历 rules ,rules 中 oneOf 非数组的不处理,数组的则进行遍历,判断 rule 下的 use 是否为数组,如果不是数组,说明是单个 loader ,那么先转化为数组,然后添加该 loader,如果是数组则直接 push 进去就可以了。

再运行一下,这样确实完成了,好了那么是否可以进一步优化呢?当然可以

优化方向

首先想到的是,我们不需要每个都增加该 loader,只需要正则能匹配 scss 结尾和 .global.scss 结尾的文件就可以了,认真看 nextjs 的 rules ,其中包含了一些以 .scss 结尾的规则和以 .global.scss 结尾以及不包含 .global 但是以 .scss 结尾的规则,那么这里有三个规则。

/\.(css|less|scss|sass)$/
/(?<!\.global)\.(scss|sass)$/
/\.global\.(scss|sass)$/
[ /\.global\.css$/, /\.global\.less$/, /\.global\.(scss|sass)$/ ]

为了适应这些规则,我们写一个方法一些判断就可以了,代码如下。

const checkNeedReplace = function(ruleTest){if(!ruleTest){return false;}if(!(ruleTest instanceof Array)){ruleTest = [ruleTest];}return ruleTest.some(rule => {if(rule.test('.global.scss') || rule.test('test.scss')){return true;}});}

由于 rules 也有是数组,有些不是,因此统一转化为数组,然后数组循环处理,判断是否存在一项满足条件的,使用 .global.scss 和 test.scss 去匹配,如果匹配就满足上面的正则条件。

有了上面方法,接下来我们只需要加一层过滤就可以了,代码如下。

webpackConfig.module.rules.forEach(      rule => {        if(rule.oneOf instanceof Array){          let cssRules = [];          rule.oneOf.forEach(cssRule => {            if(!checkNeedReplace(cssRule.test)){ // 过滤不需要的规则              cssRules.push(cssRule);              return;            }            console.log(cssRule.test);            if(cssRule.use instanceof Array){              addUserLoader(cssRule.use);            } else if(cssRule.use){              addUserLoader([cssRule.use])            }            cssRules.push(cssRule);          });          rule.oneOf = cssRules;        }            newRules.push(rule);    })

以上就完成了,那么最后我们再来看一下全部代码

webpack: (webpackConfig, { dev, isServer, buildId, defaultLoaders }) => {    let newRules = [];    const addUserLoader = function(arr){      if(!(arr instanceof Array)){return arr};      arr.push(        {          loader: 'string-replace-loader',          options: {            search: 'vars.scss',            replace: 'vars-eurp.scss'          }        }      );      return arr;    };    const checkNeedReplace = function(ruleTest){      if(!ruleTest){        return false;      }      if(!(ruleTest instanceof Array)){        ruleTest = [ruleTest];      }      return ruleTest.some(rule => {        if(rule.test('.global.scss') || rule.test('test.scss')){          return true;        }      });    }    webpackConfig.module.rules.forEach(      rule => {        if(rule.oneOf instanceof Array){          let cssRules = [];          rule.oneOf.forEach(cssRule => {            if(!checkNeedReplace(cssRule.test)){ // 过滤不需要的规则              cssRules.push(cssRule);              return;            }            console.log(cssRule.test);            if(cssRule.use instanceof Array){              addUserLoader(cssRule.use);            } else if(cssRule.use){              addUserLoader([cssRule.use])            }            cssRules.push(cssRule);          });          rule.oneOf = cssRules;        }            newRules.push(rule);    });    webpackConfig.module.rules = newRules;    return webpackConfig;  }

如果你还有其他问题,欢迎一起交流学习。

参考文章:https://segmentfault.com/a/1190000037712654

nextjs 写 css loader 处理多地区不同基础变量的方法相关推荐

  1. webpack css loader

    我们新建一个login.js文件,作为一个组件. 这里定义了一个函数,函数中创建了h2标签,然后给标签中添加文字.还有类名className,最后把这个dom返回.最后通过document.body. ...

  2. 辛星和您一起手写CSS气泡

    上文中我公布了一篇手写导航条的博客,那么这一篇博客我将和大家一起手写气泡.那么什么是气泡呢?先给那些刚入门的童鞋一个截图,来更好的认识一下什么是气泡把: 这就是一个简单的气泡啦,那么它主要用来干什么呢 ...

  3. bootstrap怎么用_不用自己写css,不用bootstrap,写样式有tailwindcss就足够了

    很多前端开发者不喜欢写css, 因为对一些属性不熟悉调试起来很费劲.还有一些开发者会选择使用一些css库,比如bootstrap, 但是bootstrap是高度定制的,写出来的风格可能并不符合设计稿. ...

  4. css 圆形背景icon_我写CSS的常用套路(附demo的效果实现与源码)

    前言 本文是笔者写CSS时常用的套路.不论效果再怎么华丽,万变不离其宗.1.交错动画 有时候,我们需要给多个元素添加同一个动画,播放后,不难发现它们会一起运动,一起结束,这样就会显得很平淡无奇.那么如 ...

  5. php html5 css样式,怎么在html页面写css样式表

    本教程操作环境:windows7系统.html5和css3版,该方法适用于所有品牌电脑. 在html页面写css样式表 1.首先可以直接把css代码写在现有的HTML标签元素的开始标签里面,并且css ...

  6. 10 个 GitHub 上超火的 CSS 技巧项目,找到写 CSS 的灵感!

    大家好,我是你们的 超级猫,一个不喜欢吃鱼.又不喜欢喵 的超级猫 ~ 如果 CSS 是女孩子,肯定如上图那样吧 ???? ~ 简介 一般人没事的时候刷刷朋友圈.微博.电视剧.知乎,而有些人是没事的时候 ...

  7. WEB UI篇——以结构化的方式写CSS

    我的职业是码农,以前有人称这职业叫程序员或软件工程师,不过这些不重要,重要的是我这次写的东西和码农几乎不相干,我接触CSS的时间不长,2年多一点,并且只有在极端的情况下我才会自己动手写CSS,例如:需 ...

  8. html中写css代码,开发DIV CSS时 先写CSS代码还是先写HTML代码

    相信良多LOVE用DIV+CSS技术启示重构网页的爱好者友好,在起源学习DIV+CSS的时分都邑想一个标题,想晓得DIV+CSS妙手或有教育者在开发制作html页面的时刻,下场是先写html照样先写c ...

  9. 在react项目中编写css,更好的在react项目中写css代码--emotion

    简介: emotion是一个JavaScript库,使用emotion可以用写js的方式写css代码.在react中安装emotion后,可以很方便进行css的封装,复用.使用emotion后,浏览器 ...

最新文章

  1. UI+UE+UX+区别
  2. git提交时支持文件名大小写的修改
  3. python list删除元素_python中List添加、删除元素的几种方法
  4. leetcode 39. Combination Sum | 39. 组合总和(Java)
  5. .NET的Snk使用方法
  6. [html] iframe父页面如何获取子页面的元素?
  7. 列主元消去法例题详解_高斯列主元消元法解方程组的步骤
  8. 201671030107 胡文艳 实验十四 团队项目评审课程项目总结
  9. fedora下安装python
  10. Python SPSS教程
  11. .Net 中使用 iTextSharp 组件生成 PDF
  12. 什么是操作系统啊 | 战术后仰
  13. FPGA实现360°SG90舵机
  14. Python多线程实现 as_completed先返回的任务先处理 在 阿里云 函数式计算 优化的应用
  15. 青少年编程教育平台后台—登录注册(界面设计)
  16. 修了一天的kali外置网卡,重装了n遍系统后..
  17. 日均5亿查询量,京东到家订单中心ES架构演进
  18. Ubuntu设置仅允许特定用户或特定IP通过ssh访问
  19. 数值分析之牛顿拉夫森迭代(牛顿法)
  20. python爬虫之request.get()参数

热门文章

  1. python如何拟合函数_我们如何在Python中拟合一个sigmoid函数?(How do we fit a sigmoid function in Python?)...
  2. 河南大学计算机类课程表,河南大学课程表大曝光!直击最满课的学院!
  3. t12电烙铁c语言程序,做一把精致的T12数控电烙铁
  4. 我会记着你,然后爱别人----精美语段选摘
  5. 下载64位oracle.dataaccess.dll,oracle.dataaccess.dll 文件下载
  6. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java校园二手交易平台的设计与实现662p4
  7. CSS背景图片定位(background-position,css sprit,背景定位,background-imag
  8. 小软件推荐 - PPT遥控器
  9. Axure绘制密码输入框
  10. 从Nuget官网上下载指定版本Nuget包