最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 在react-native 项目中使用yarn link

    正文概述 掘金(RoyLuo)   2021-02-25   612

    最近把项目中沉淀出来的一些工具函数整理出来编写成一个代码仓库,准备先在本地把每个函数都调试一遍之后再发布,需要使用yarn link 或者npm link 在测试的项目中link 指定的本地依赖库,在这过程中遇到一些问题

    问题

    在React Native 项目下无法使用yarn link 或者npm link 来link 本地的依赖,原因是RN 使用的打包工具Metro 不支持symlinks

    逛了一番issues 后,找到了一个可行的解决方案

    解决方案

    使用第三方库metro-symlinked-deps

    这个库可以用来自定义metro 的打包配置,使用方法可以参考metro-symlinked-deps 的文档

    这里贴一下metro-symlinked-deps 给出的例子

    // metro.config.js
    
    const {
        applyConfigForLinkedDependencies,
    } = require('@carimus/metro-symlinked-deps');
    
    module.exports = applyConfigForLinkedDependencies(
        {
            transformer: {
                getTransformOptions: async () => ({
                    transform: {
                        experimentalImportSupport: false,
                        inlineRequires: false,
                    },
                }),
            },
        },
        {
            projectRoot: __dirname,
            blacklistLinkedModules: ['react-native'],
        },
    );
    

    但是在使用这个库的时候也遇到了一些问题

    另一个问题

    一开始使用这个库并没有解决yarn link 无效的问题。确定自己配置没错之后,就开始寻找问题。因为看到有人说这个库有用,有人说没用。就开始看这个库的源码,看看它到底干了啥

    于是,发现这个库会拿到项目下node_modules 里面使用symlink 的依赖的真实地址。

    那么按理来说我用yarn link 是符合他的这个逻辑的, 并且我使用ls -l 命令查看我link 的本地依赖也是正确返回了软链的地址。于是带着疑问我查看了这个库用来收集link 的依赖的方法,最终发现这个库使用了get-dev-paths 来检查link 的依赖

    /**
     * Resolve all detected linked directories to unique absolute paths without a trailing slash.
     *
     * @param {string} projectRoot
     */
    function resolveDevPaths(projectRoot) {
        return Array.from(
            new Set(
                getDevPaths(projectRoot)
                    .map((linkPath) => {
                        return `${fs.realpathSync(linkPath)}`.replace(/\/+$/, '');
                    })
                    .filter((absLinkPath) => !!absLinkPath),
            ),
        );
    }
    

    所以目光来到了get-dev-paths

    首先看看它是如何返回link 的依赖的

    addPath = function(dep) {
      var target;
      if (!fs.lstatSync(dep).isSymbolicLink()) {
        return;
      }
      try {
        target = realpath.sync(dep);
      } catch (error) {
        err = error;
        return typeof opts.onError === "function" ? opts.onError(err) : void 0;
      }
      // Skip target paths with "/node_modules/" in them.
      if (nodeModulesRE.test(target)) {
        return typeof opts.onError === "function" ? opts.onError(new Error(`Symlink leads to nothing: '${dep}'`)) : void 0;
      }
      if (opts.preserveLinks) {
        paths.push(dep);
      }
      if (!visited.has(target)) {
        visited.add(target);
        if (!opts.preserveLinks) {
          paths.push(target);
        }
        queue.push(dep);
      }
    };
    

    addPath 方法通过判断一个文件路径是否是软链,并文件的真实路径添加最终的输出结果中

    那么addPath 在哪调用的呢,在这个库的源码里发现下面这段代码

    return fs.readdirSync(depsDir).forEach(function(name) {
            var scope;
            if (name[0] === '.') { // Skip hidden directories.
              return;
            }
            if (name[0] === '@') {
              scope = name;
              fs.readdirSync(path.join(depsDir, name)).forEach(function(name) {
                if (deps[name = scope + '/' + name]) {
                  return addPath(path.join(depsDir, name));
                }
              });
            } else if (deps[name]) {
              addPath(path.join(depsDir, name));
            }
          });
    

    上面代码中deps[name]deps是获取了项目目录下的package.json中的dependencies 里的依赖,并且与fs.readdirSync方法获取的文件名来比对,如果文件名出现在了dependencies 就执行addPath方法来获取真实路径并添加到最终结果中。

    于是我发现,我使用yarn link 的依赖的名字并没有出现在我的package.json中的dependencies 里,于是我在package.json 中的dependencies 里添加了本地依赖的名字

    "dependencies": {
        "myPackageName" : "*"
    },
    

    再次尝试react-native start ,终于编译成功。

    One more thing

    到这里就可以开始测试自己的本地依赖了,但是还有一个小小问题,可能会报错。本地依赖的依赖找不到了。这时候需要改一下配置

    // metro.config.js
    
    const {
        applyConfigForLinkedDependencies,
    } = require('@carimus/metro-symlinked-deps');
    
    module.exports = applyConfigForLinkedDependencies(
        {
            transformer: {
                getTransformOptions: async () => ({
                    transform: {
                        experimentalImportSupport: false,
                        inlineRequires: false,
                    },
                }),
            },
        },
        {
            projectRoot: __dirname,
            blacklistLinkedModules: ['react-native'],
            // 新增这个
    	      resolveNodeModulesAtRoot: true 
        },
    );
    

    终于可以在React Native 项目中调试本地依赖了~

    最后

    以上是我寻找在React Native 项目中使用yarn link的解决办法的全过程。

    参考

    • metro-symlinked-deps
    • get-dev-paths

    起源地下载网 » 在react-native 项目中使用yarn link

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元