使用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的文件都不会被插件应用。

相关推荐
qq. 28040339844 小时前
CSS层叠顺序
前端·css
喝拿铁写前端4 小时前
SmartField AI:让每个字段都找到归属!
前端·算法
猫猫不是喵喵.4 小时前
vue 路由
前端·javascript·vue.js
烛阴5 小时前
JavaScript Import/Export:告别混乱,拥抱模块化!
前端·javascript
bin91535 小时前
DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例12,TableView16_12 拖拽动画示例
前端·javascript·vue.js·ecmascript·deepseek
GISer_Jing5 小时前
[Html]overflow: auto 失效原因,flex 1却未设置min-height &overflow的几个属性以及应用场景
前端·html
程序员黄同学6 小时前
解释 Webpack 中的模块打包机制,如何配置 Webpack 进行项目构建?
前端·webpack·node.js
拉不动的猪6 小时前
vue自定义“权限控制”指令
前端·javascript·vue.js
再学一点就睡6 小时前
浏览器页面渲染机制深度解析:从构建 DOM 到 transform 高效渲染的底层逻辑
前端·css
拉不动的猪6 小时前
刷刷题48 (setState常规问答)
前端·react.js·面试