使用Create React Native App和Expo在React Native中构建时自定义代码

时间:2018-06-08 04:42:43

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

通常,有没有办法在构建步骤中自定义应用程序代码?

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

    由于服务器和应用程序位于不同的主机上(使用Android模拟器或实际的物理设备时),因此
  • localhost无法正常工作。
  • 同一网络中主机的实际IP地址有效,但在多开发人员项目中,每个人都不得不经常将代码中的常量IP更改为其开发机器的IP。

使用Webpack可以通过DefinePlugin替换占位符来解决构建正在发生的机器的IP地址。

1 个答案:

答案 0 :(得分:0)

我们最终使用了受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')