使用postcss-px-to-viewport-8-plugin将页面转响应式

使用postcss-px-to-viewport-8-plugin将页面转响应式

背景

公司最近接了个项目,其中要求部分页面在移动端正常显示,第一方案是使用响应式,但是设计稿最后出的和Web端差别较大同时两端的功能不是完全对齐的,所以决定使用两个模块去实现,通过路由来控制显示的页面。

说到这里第一时间想到的当然是大名鼎鼎的postcss-px-to-viewport插件咯,之前也用过不少次了,非常香,这次也理所当然的打算使用该方案。

postcss-px-to-viewport使用

因为我们使用的是next,next已经内置了postcss插件,所以我们下载postcss-px-to-viewport即可

css 复制代码
 pnpm install postcss-px-to-viewport --save-dev

然后在next项目的根目录创建postcss.config.js文件并添加如下配置

javascript 复制代码
 module.exports = {
   plugins: {
     'postcss-px-to-viewport': {
       viewportWidth: 375, // 设计稿的视口宽度,假设设计稿宽度为 375px
       unitPrecision: 5, // 转换后的单位精度
       viewportUnit: 'vw', // 转换后的单位
       selectorBlackList: [], // 忽略的选择器
       minPixelValue: 1, // 最小的转换值
       mediaQuery: false, // 是否转换媒体查询中的 px
       exclude: /node_modules/, // 忽略的文件或文件夹
     },
   },
 };

具体的配置网上很多了,这里贴一个文档地址吧,需要的可以自己选择自己的配置👉 github.com/evrone/post...

postcss-px-to-viewport部分配置不生效

配置完毕以后打包,啊哦,出现了一个打包错误,让我们来看看:

原来是一个类型错误,无伤大雅,我们解决了以后接着打包,怎么打包失败?

原来是权限问题,我们用管理员运行然后打包,打包成功!,现在我们来检查一下打包产物里面的css有没有更改单位。

非常好,已经成功转成vw响应式了,但是根据模块检查发现是所有的页面都转vw了,而我只想转部分页面的单位,我们检查一下是不是部分配置项没有生效?

因为postcss-px-to-viewport支持include配置,所以我在想是不是我配置写的有问题,于是在尝试好几次不同的正则写法后打包的产物依然没变,连文件指纹都不带改的。。。

因为打包的时候为了检测配置项是否正确加载了,所以我在配置文件加了一行打印

js 复制代码
    basconsole.log('Loading postcss.config.js');
     ​
     module.exports = {
       plugins: {
         'postcss-px-to-viewport': {
           viewportWidth: 375, // 设计稿的视口宽度,假设设计稿宽度为 375px
           ...
         },
       },
     };

然后我发现控制台出现了这样的信息:

bash 复制代码
    Loading postcss.config.js
     postcss-px-to-viewport: postcss.plugin was deprecated. Migration guide:
     https://evilmartians.com/chronicles/postcss-8-plugin-migration

然后我看了下,发现是postcss8换写法了,得升级,于是我检查了一下next自带的postcss版本,发现是8.4.14 的版本。这个时候我查了下,发现得换插件了,也就是postcss-px-to-viewport-8-plugin

postcss-px-to-viewport-8-plugin的使用

postcss-px-to-viewport-8-plugin使用和postcss-px-to-viewport是一样的,只需要将插件名称更改一下即可。

js 复制代码
 module.exports = {
       plugins: {
         'postcss-px-to-viewport-8-plugin': {
           viewportWidth: 375, // 设计稿的视口宽度,假设设计稿宽度为 375px
           unitPrecision: 5, // 转换后的单位精度
           viewportUnit: 'vw', // 转换后的单位
           ...
         },
       },
     };
     

然后我们接着打包看看。OK打包完成,检查一下css,发现和上面一样,单位是转换了,但是是全局的,include并没有生效,事已至此没办法了,只能看看源码调试一下了。

排查include配置不生效

插件的目录很清晰,我们可以看到入口文件是lib文件夹下的index.js

js 复制代码
         css.walkRules(rule => {
             // Add exclude option to ignore some files like 'node_modules'
             const file = rule.source?.input.file || '';
             if (opts.exclude && file) {
               if (Object.prototype.toString.call(opts.exclude) === '[object RegExp]') {
                 if ((0, _utils.isExclude)(opts.exclude, file)) return;
               } else if (
                 // Object.prototype.toString.call(opts.exclude) === '[object Array]' &&
                 opts.exclude instanceof Array) {
                 for (let i = 0; i < opts.exclude.length; i++) {
                   if ((0, _utils.isExclude)(opts.exclude[i], file)) return;
                 }
               } else {
                 throw new Error('options.exclude should be RegExp or Array.');
               }
             }
           ....

可以看到exclude的配置如上所示,但是并没有include的配置,难不成这个配置不在index.js吗,但是没有找到,这里先暂且按下不表,先检查一下include的正则匹配有没有问题,打印上面的file以及正则匹配结果,发现无法匹配

js 复制代码
  const reg = //src/app/mobile//

有经验的应该一眼就能看出来,是因为windows系统的路径符号导致的,windows应该用下面的正则:

js 复制代码
     const reg = /\src\app\mobile\/

现在是可以匹配了,但是打包产物依然不生效,我现在怀疑include配置根本就没有实现,于是我们去仓库看看他的源码。👉传送门

找了一圈,发现确实没有实现include,然后我就想这么大的问题别人没有发现吗,看了下Issues是有的github.com/lkxian888/p...

解决

最好的方式当然是提PR了,但是时间紧任务重啊,只能先改插件了。

1.直接修改插件

在项目的node_modules中找到postcss-px-to-viewport-8-plugin文件夹,然后在该文件夹下的lib文件夹下的index.js中的css.walkRules的参数方法中(也就是第60行)添加下面的代码:

js 复制代码
 if (opts.include && file) {
               if (Object.prototype.toString.call(opts.include) === '[object RegExp]') {
                 if (!(0, _utils.isExclude)(opts.include, file)) return;
               } else if (opts.include instanceof Array) {
                 let included = false;
                 for (let i = 0; i < opts.include.length; i++) {
                   if ((0, _utils.isExclude)(opts.include[i], file)) {
                     included = true;
                     break;
                   }
                 }
                 if (!included) return;
               } else {
                 throw new Error('options.include should be RegExp or Array.');
               }
             }

其实就是和exclude反着来就行。

2. 使用exclude

因为我们打包部署用的是容器,所以改本地文件是不行嘞,那就只能退而求其次选择使用exclude了

js 复制代码
    module.exports = {
       plugins: {
         'postcss-px-to-viewport-8-plugin': {
           viewportWidth: 375, // 设计稿的视口宽度,假设设计稿宽度为 375px
           unitPrecision: 5, // 转换后的单位精度
           viewportUnit: 'vw', // 转换后的单位
           selectorBlackList: [], // 忽略的选择器
           minPixelValue: 1, // 最小的转换值
           mediaQuery: false, // 是否转换媒体查询中的 px
           // exclude: /node_modules/, // 忽略的文件或文件夹
           exclude: /^(?:(?!mobile).)*$/, 
         },
       },
     };

这下路径有mobile的文件都不会被插件应用。

相关推荐
牧羊狼的狼4 小时前
React 中的 HOC 和 Hooks
前端·javascript·react.js·hooks·高阶组件·hoc
知识分享小能手5 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
魔云连洲5 小时前
深入解析:Vue与React的异步批处理更新机制
前端·vue.js·react.js
mCell6 小时前
JavaScript 的多线程能力:Worker
前端·javascript·浏览器
超级无敌攻城狮7 小时前
3 分钟学会!波浪文字动画超详细教程,从 0 到 1 实现「思考中 / 加载中」高级效果
前端
excel8 小时前
用 TensorFlow.js Node 实现猫图像识别(教学版逐步分解)
前端
gnip8 小时前
JavaScript事件流
前端·javascript
赵得C9 小时前
【前端技巧】Element Table 列标题如何优雅添加 Tooltip 提示?
前端·elementui·vue·table组件
wow_DG9 小时前
【Vue2 ✨】Vue2 入门之旅 · 进阶篇(一):响应式原理
前端·javascript·vue.js
weixin_456904279 小时前
UserManagement.vue和Profile.vue详细解释
前端·javascript·vue.js