我正在为项目构建网络(react
和webpack
)和移动应用(babel
和react-native
)。因此,我为业务逻辑和redux / api库创建了一个公共库。
网络和移动设备之间的某些代码会稍有不同。就我而言,它是localStorage vs AsyncStorage,我将其用于身份验证...
我正在尝试为构建阶段传递环境变量,以切换某些文件的导入,以便为每个构建加载正确的文件,这些文件只是路径链接(即没有预构建)我图书馆的expo
)例如:
import '../mylib'
尝试1
if(PLATFORM === 'mobile'){
import StorageModule from './mobile-storage-module`
} else {
import StorageModule from './mobile-storage-module`
}
export default StorageModule
说说它是移动设备还是网络设备,以便它根据不同的构建导入不同的库,如下所示:
我的@babel/preset-env
拥有:
.babelrc
然后在本地存储文件中执行以下操作:
{
"presets": [
[
"@babel/preset-env",
{
"platform": "mobile"
}
]
]
}
那没用,这对我也没用。
尝试2
我安装了react-native-dotenv并使用以下内容创建了export default () => {
const platform = process.env.platform
if (platform === 'mobile') {
return import './storage-modules/storage-mobile'
}
return import './storage-modules/storage-web'
}
文件:
.env
并在我的PLATFORM=mobile
中设置插件:
.babelrc
在示例文件中,我尝试了此操作:
{
"presets": [
"babel-preset-expo",
"react-native-dotenv"
]
}
但是现在我的构建无法正常工作。知道我如何在适用于react-native应用程序和Webpack构建(也使用babel)的babel的构建过程中进行动态导入吗?
答案 0 :(得分:2)
首先,@babel/preset-env
并没有您认为的那样。这不是为了指定您自己的变量,而是一个插件,可以针对您要支持的浏览器自动使用正确的目标和填空信息。
获取环境变量的最简单方法是使用webpack define插件(它是webpack的一部分,因此无需安装任何额外的东西)
只需将其添加到您的webpack配置中即可。
plugins: [
new webpack.DefinePlugin({
'process.env': {
platform: 'mobile',
},
}),
],
接下来,您不能在ifs内使用普通的import
语句。
import
在运行任何代码之前都已解决,无论是通过webpack生成,还是在脚本加载受支持的环境中。
要在运行时导入某些内容,您需要使用动态导入。
这是一个看起来像这样的例子。
export default new Promise(async resolve => {
resolve(
process.env.platform === 'mobile'
? (await import('./mobile.js')).default
: (await import('./desktop.js')).default
);
});
您现在可以像往常一样从该文件导入,但是请注意,默认导出是一个承诺。
答案 1 :(得分:1)
问题标题为“ 在babel构建阶段”,我假设您想为台式机和移动设备创建不同的版本(而不是为两者构建一个版本,而是在运行时动态加载所需的模块)。所以我会这样:
在package.json
中为台式机和移动设备定义运行脚本:
"scripts": {
"devmobile": "cross-env NODE_ENV=development PLATFORM=mobile webpack --progress",
"dev": "cross-env NODE_ENV=development webpack --progress",
}
...,或者您可以为台式机和移动设备版本创建两个不同的webpack.config.js
文件,但我认为上述操作更容易...
然后npm run devmobile
构建用于移动设备,npm run dev
构建用于桌面。
由于我在Windows上,因此我使用cross-env
package,但这是建议的独立于操作系统的方法。
然后我将使用Webpack的NormalModuleReplacementPlugin
:
(基于this exmaple)
在您的webpack.config.js中:
// defining the wanted platform for the build (comfing form the npm run script)
const targetPlatform = process.env.PLATFORM || 'desktop';
// then use the plugin like this
plugins: [
new webpack.NormalModuleReplacementPlugin(/(.*)-PLATFORM(\.*)/, function(resource) {
resource.request = resource.request.replace(/-PLATFORM/, `-${targetPlatform}`);
}),
]
...那么,如果您具有这两个文件:
./storage-modules/storage-mobile.js
./storage-modules/storage-desktop.js
像这样在脚本中导入所需的内容:
import './storage-modules/storage-PLATFORM';
这样,生成的构建将仅包含用于构建过程的当前PLATFORM所需的文件。
另一种可能的解决方案可能是ifdef-loader,但我尚未对其进行测试。也许值得尝试,似乎很简单。
如果您希望构建一个版本并动态导入所需的模块,则可以在app.js
(或其他任何方法)中执行以下操作:
// this needs to have defined when the app is running
const targetPlatform = process.env.PLATFORM || 'desktop';
import(
/* webpackChunkName: "[request]" */
`./storage-modules/storage-${targetPlatform}`
).then(storageModule => {
// use the loaded module
});
或:
(async () => {
const storageModule = await import(
/* webpackChunkName: "[request]" */
`./storage-modules/storage-${targetPlatform}`
);
// use the loaded module
})();
要使其正常运作,Babel必须为configured。
有关具有动态导入here的Webpack的更多信息。
答案 2 :(得分:0)
您可以使用transform-inline-environment-variables来将平台传递给babel
"build-mobile": "PLATFORM=mobile ...",
"build-app": "PLATFORM=app ...",