babel-plugin-react-native-image-to-base64图片转Base64

babel-plugin-react-native-image-to-base64通过babel用于react-native构建时把图片转换为base64放到bundle文件中。

背景

react-native默认图片放在Assets文件夹中,但是就无法动态更新,如果全部放在服务器,小的图标也会占用请求链接,为了解决这个问题,我们需要把图片转成base64放到bundle文件里面,这样既能动态更新有解决了小图片的访问问题。

babel-plugin-react-native-image-to-base64 使用

1、安装

1
yarn add -D babel-plugin-react-native-image-to-base64

or

1
npm install --save-dev babel-plugin-react-native-image-to-base64

2、babel.config.js 配置
插件支持配置图片的大小来选择是否转换为base64

1
2
3
4
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [['react-native-image-to-base64', {limit: 2 * 1024}]],
};

3、转换后效果
构建前文件

1
2
3
4
<Image
source={require('./button.png')}
style={{ width: 859, height: 95 }}
/>

构建后文件:

1
n.default.createElement(T.Image,{source:{uri:"data:image/png;base64,jifsfs....",width:590,height:96},style:{width:859,height:95}})

这样图片就可以直接打包到bundle文件中
4、转换原理
在babel中检测到图片的require引用,然后通过解析文件路径,读取到图片地址

1
2
3
4
5
6
7
8
9
10
11
12
const { opts: { limit = LIMIT, test = FILE_TEST }, file: { opts: { filename } } } = source;
if (t.isIdentifier(ast.node.callee, { name: 'require' }) && ast.node.arguments.length === 1) {
if (t.isStringLiteral(ast.node.arguments[0]) && test.test(ast.node.arguments[0].value)) {
const resolveFilePath = filename.substring(0, filename.lastIndexOf("/") + 1);//获取引用图片的文件路径
const filePath = nodePath.resolve(resolveFilePath, ast.node.arguments[0].value);//读取到图片地址
const data = fs.readFileSync(filePath);
if (data.length < limit) {
const source = buildImageSource(t, filePath);
ast.replaceWith(source);
}
}
}

图片转成base64

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const buildImageSource = (t: typeof Types, imgPath: string) => {
const fileMimeType = mimeType.lookup(imgPath);
const data = fs.readFileSync(imgPath);
const buff = Buffer.from(data).toString('base64');
const base64 = 'data:' + fileMimeType + ';base64,' + buff;
const dimensions = require('image-size')(imgPath);
const source = t.objectExpression([
t.objectProperty(
t.identifier('uri'),
t.stringLiteral(base64),
),
t.objectProperty(
t.identifier('width'),
t.numericLiteral(dimensions.width)
),
t.objectProperty(
t.identifier('height'),
t.numericLiteral(dimensions.height)
),
]);
return source;
}