【问题标题】:Customizing code at build-time in React Native with Create React Native App and Expo使用 Create React Native App 和 Expo 在 React Native 的构建时自定义代码
【发布时间】:2018-11-18 02:13:27
【问题描述】:

一般来说,有没有办法在构建步骤中自定义应用代码?

具体来说,通常需要从应用程序向本地后端([1][2][3][4])发出请求。

  • localhost 不起作用,因为服务器和应用程序位于不同的主机上(使用 Android 模拟器或实际物理设备时)。
  • 主机的实际 IP 地址在同一网络中有效,但在多开发者项目中,每个人都需要不断地将代码中的恒定 IP 更改为他们开发机器的 IP 地址。

使用 Webpack,可以通过 DefinePlugin 将占位符替换为正在构建的机器的 IP 地址来解决此类情况。

【问题讨论】:

    标签: react-native expo create-react-native-app


    【解决方案1】:

    我们最终使用了受react-native-typescript-transformerreact-native-sass-transformer 等变形金刚启发的有点老套的方法。它的想法几乎等同于 Webpack 中提到的DefinePlugin

    首先,项目目录中的一些转换器文件(您可以随意命名它们,只需更新引用即可):

    configBuildReplacements.js

    // whatever logic you need
    
    module.exports = {
        API_HOST_PLACEHOLDER: `http://${getLocalNetworkAddress()}:3000`,
        SOME_OTHER_DYNAMIC_VALUE: someFun(),
    }
    

    configBuildReplaceTransformer.js

    const semver = require('semver')    
    
    let upstreamTransformer = null
    
    const reactNativeVersionString = require('react-native/package.json').version
    const reactNativeMinorVersion = semver(reactNativeVersionString).minor
    
    if (reactNativeMinorVersion >= 56) {
        upstreamTransformer = require('metro/src/reactNativeTransformer')
    }
    else if (reactNativeMinorVersion >= 52) {
        upstreamTransformer = require('metro/src/transformer')
    }
    else if (reactNativeMinorVersion >= 47) {
        upstreamTransformer = require('metro-bundler/src/transformer')
    }
    else if (reactNativeMinorVersion === 46) {
        upstreamTransformer = require('metro-bundler/build/transformer')
    }
    else {
        // handle RN <= 0.45
        const oldUpstreamTransformer = require('react-native/packager/transformer')
        upstreamTransformer = {
            transform({ src, filename, options }) {
                return oldUpstreamTransformer.transform(src, filename, options)
            },
        }
    }
    
    
    module.exports.transform = function (src, filename, options) {
        // handle RN >= 0.46
        if (typeof src === 'object') {
            ({ src, filename, options } = src)
        }
    
        const replacements = require('./configBuildReplacements')
    
        const modifiedSrc = Object.keys(replacements).reduce(
            (src, replacementKey) => src.replace(
                new RegExp(replacementKey, 'g'),
                replacements[replacementKey],
            ),
            src,
        )
    
        return upstreamTransformer.transform({
            src: modifiedSrc,
            filename,
            options,
        })
    }
    

    导出的transform 函数使用从上一个文件configBuildReplacements.js 导出的对象作为字典,在将此代码交给默认(上游)转换器之前,将源代码中的键子字符串替换为值子字符串。

    并将这个新变压器连接到项目:

    • 使用 Expo,将 transformer 打包程序选项添加到 app.json

      {
        "expo": {
          "packagerOpts": {
            "transformer": "configBuildReplaceTransformer.js"
          }
        }
      }
      
    • 如果没有 Expo,请将 getTransformModulePath() 添加到 rn-cli.config.js(这是 React Native CLI 的可选配置文件的默认路径,在撰写本文时该文件的文档非常少):

      module.exports = {
          getTransformModulePath() {
              return require.resolve('./configBuildReplaceTransformer')
          },        
      }
      

    完成后,就像DefinePlugin,代码一样

    get('API_HOST_PLACEHOLDER/info')
    

    会变成这样的

    get('http://192.168.42.23:3000/info')
    

    【讨论】:

      猜你喜欢
      • 2018-06-04
      • 2018-09-07
      • 1970-01-01
      • 2022-10-07
      • 2018-10-27
      • 2019-04-01
      • 2017-10-21
      • 1970-01-01
      • 2017-10-27
      相关资源
      最近更新 更多