jiangjiu / blog-md

前端/健身 思考与笔记~
https://github.com/jiangjiu/blog-md/issues
86 stars 6 forks source link

windows/linux下path路径不一致的问题 #47

Open jiangjiu opened 6 years ago

jiangjiu commented 6 years ago

之前写的san-webpack-loader在近期的几个运营项目的生产环境中进行了实践,很幸运的是并没有什么太大的问题,提高了开发体验和效率。

然而,就在新项目重新开坑的时候,一个让人意想不到的问题出现了:

一个新同学配发了windows本,新的环境竟然跑不起来。。

0DF8F1F5B03021900E157718067891AE

折磨了半天多的时间,终于把这个bug修了,在此总结一下。

问题

在Mac环境中,路径分隔符是/san-webpack-loader中,需要将.san文件的style标签抽离,计算成webpack4的内联loader引入。

 const styleLoader = isProduction
        ? `!${rootContext}/node_modules/mini-css-extract-plugin/dist/loader.js`
        : '!style-loader';

涉及到路径计算及拼接时,想当然的就直接用/进行了字符串拼接。

但是!!!,windows环境的路径分隔符是正好相反的\反向斜杠。。。 在windows中编译出来的代码是这样的:

// 正反斜杠都存在了
import 'D:\work\aaa\bbb\node_modules/nimi-css-extract-plugin/dist/loader.js'

很明显这是不行的。

之前上线的几个项目中,开发同学清一色的mac💻,完美的避开了windows环境这个差异。

Node.js的path模块

怎么解决呢?

Node.js的path模块了解一下。

先来看几个东东。

path.join && path.resolve

业务中最常用的两个api了,处理相对路径及绝对路径。

path.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// Mac中  返回: '/foo/bar/baz/asdf'

Mac中返回的就很正常。

D579266EB4EA45D8B010D7C68CB5C5AA windows中,会返回双反斜杠的结果。

值得注意的是,即使join的参数中带有正斜杠 / ,windows环境下也会处理成反斜杠。

path.sep

这个字段提供了平台特定的路径片段分隔符:

Windows 上是 \ POSIX 上是 / 例如,在 POSIX 上:

'foo/bar/baz'.split(path.sep);
// 返回: ['foo', 'bar', 'baz']

在 Windows 上:

'foo\\bar\\baz'.split(path.sep);
// 返回: ['foo', 'bar', 'baz']

注意:在 Windows 上,斜杠字符(/)和反斜杠字符(\)都可作为路径分隔符; 但 path 的方法只添加反斜杠(\)。

问题again

有了上述一些Api,很自然的想到可以将路径先分隔开,再通过path.join/path.resolve下的API进行处理,就可以得到统一的路径字符串了(都是正斜杠/都是反斜杠)。


import 'D:\work\aaa\bbb\node_modules\nimi-css-extract-plugin\dist\loader.js'
// windows下的处理结果 o(╥﹏╥)o

解bug,一次过是不存在的,遇到更多的bug,这才是生活。

很显然,我忽略了一个重要的问题:这个路径字符串是要丢给es modules处理的。 人家不认反斜杠。。。

也就是说,我需要把windows/mac下的字符串统一成正斜杠才行

path.posix

POSIX,Portable Operating System Interface。

是UNIX系统的一个设计标准,很多类UNIX系统也在支持兼容这个标准,如Linux。

遵循这个标准的好处是软件可以跨平台。 所以windows也支持就很容易理解了,那么多优秀的开源软件,支持了这个这些软件就可能有windows版本,就可以完善丰富windows下的软件。

大名鼎鼎的POSIX标准,在path下也有实现。

举个栗子:

path.posix.join('/foo', 'bar', 'baz/asdf', 'quux', '..');
// windows中  也会返回: '/foo/bar/baz/asdf'

任何环境下,都会返回unix标准的结果,这个API简直是不能再赞了👍

问题again😤

有了上面的API,应该是可以统一成正斜杠了吧?

然后,这就是生活。

另一个问题来了,绝对路径...看下面这个例子:

// 业务中上层传递过来了一个特殊的rootContext变量
// 无法确定是否是绝对路径还是相对路径
path.posix.join(...rootContext.split(path.sep))

// 如果rootContext是一个绝对路径, 就会变成这样
 path.posix.join(...'/User/xxx/a/b'.split(path.sep))
// Mac下 'User/xxx/a/b'

 path.posix.join(...'D:\\xxx\\a\\b'.split(path.sep))
// windows下 'D:/xxx/a/b'

这种情况下,windows是可以了,但是Mac下因为提前分割了路径,join后丢掉了绝对路径的那个行首斜杠。

解决

if (/^win/.test(require('os').platform())) {
// windows环境 
...

总结

团队生产力工具大一统🖥,实在是太TM重要了。

参考