create-react-app 和electron项目整合:解决打包后无法加载图片问题

在整合基于create-react-app创建的react项目和electron时,遇到一个问题:在开发模式,可以正常加载图片,但执行electron-packager . 命令把项目打包成exe文件后,图片无法加载,控制台报错提示 NOT_FOUND,加载的图片根路径是系统盘根目录,而代码中是相对路径,按道理来说,根路径应该是项目根目录。

控制台提示如下:

《create-react-app 和electron项目整合:解决打包后无法加载图片问题》

先介绍我最终使用的解决方法:
第一步:执行npm run eject,

yarn eject

yarn run v1.17.3

$ react-scripts eject

NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting:
https://reactjs.org/blog/2018…

? Are you sure you want to eject? This action is permanent. (y/N) y

执行完后重新启动项目,失败,此时报错如下:

[0] Failed to compile.

[0]

[0] ./src/index.js

[0] Error: [BABEL] F:Reactelectronreact-material-dashboardsrcindex.js: Cannot find module ‘@babel/plugin-syntax-jsx’ (While processing: “F:\React\electron\react-material-dashboard\node_modules\babel-preset-react-app\index.js$1$0”)

[0] at Array.reduce (<anonymous>)

需要删掉node_module文件重新安装依赖,再次启动,启动成功。

第二步:修改配置文件config/webpack.config.js,在module.rules数组中,图片加载规则处添加isEnvDevelopment && ,让该规则只作用于开发模式下:

 oneOf: [
            // "url" loader works like "file" loader except that it embeds assets
            // smaller than specified limit in bytes as data URLs to avoid requests.
            // A missing `test` is equivalent to a match.
            isEnvDevelopment && {
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
              loader: require.resolve('url-loader'),
              options: {
                limit: 10000,
                name: 'static/media/[name].[hash:8].[ext]',
              },
            },

跟问题相似的issue有:https://github.com/electron-r…
这个issue中,作者描述的问题跟我遇到的一模一样,
《create-react-app 和electron项目整合:解决打包后无法加载图片问题》
根据第一个答案,需要删除webpack.config.production.js中 {test…. loader:’url-loader’},
《create-react-app 和electron项目整合:解决打包后无法加载图片问题》
create-react-app隐藏了webpack配置的详细信息,所以先通过执行npm run eject暴露webpack配置,
在webpack.config.js找到相同的配置:
《create-react-app 和electron项目整合:解决打包后无法加载图片问题》
删除这两行代码,重新打包,图片可以正常加载。
猜测问题可能是url-loader引起的,那么url-loader是干什么的呢?
参考这篇文章:webpack file-loader和url-loader的区别

file-loader可以解析项目中的url引入(不仅限于css),根据我们的配置,将图片拷贝到相应的路径,再根据我们的配置,修改打包后文件引用路径,使之指向正确的文件。如果图片较多,会发很多http请求,会降低页面性能。这个问题可以通过url-loader解决。url-loader会将引入的图片编码,生成dataURl。相当于把图片数据翻译成一串字符。再把这串字符打包到文件中,最终只需要引入这个文件就能访问图片了。当然,如果图片较大,编码会消耗性能。因此url-loader提供了一个limit参数,小于limit字节的文件会被转为DataURl,大于limit的还会使用file-loader进行copy。

url-loader和file-loader是什么关系呢?简答地说,url-loader封装了file-loader。url-loader不依赖于file-loader,即使用url-loader时,只需要安装url-loader即可,不需要安装file-loader,因为url-loader内置了file-loader。通过上面的介绍,我们可以看到,url-loader工作分两种情况:1.文件大小小于limit参数,url-loader将会把文件转为DataURL;2.文件大小大于limit,url-loader会调用file-loader进行处理,参数也会直接传给file-loader。因此我们只需要安装url-loader即可。

发起http请求。。。url-loader会将引入的图片编码,众所周知,electron打包后,访问文件是通过file协议,而不是http协议,至此,问题根源定位到了。
那么解决方法应该是放弃使用url-loader加载图片,而直接用file-loader就可以了。
但我又希望在开发时,保持原本的url-loader不变,所以webpack.config.js中图片加载的规则改成

 oneOf: [
            // "url" loader works like "file" loader except that it embeds assets
            // smaller than specified limit in bytes as data URLs to avoid requests.
            // A missing `test` is equivalent to a match.
            isEnvDevelopment && {
              test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
              loader: require.resolve('url-loader'),
              options: {
                limit: 10000,
                name: 'static/media/[name].[hash:8].[ext]',
              },
            },

还有另一种不需要执行npm run eject命令的方法:通过安装react-app-rewired模块来更改项目的webpack配置。另外,安装customize-cra模块简化配置项。
方法具体步骤:
1、安装模块
yarn add react-app-rewired customize-cra

2、修改package.json文件

/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test",
+   "test": "react-app-rewired test",
}

3、在项目根目录下添加config-overrides.js文件,添加以下内容:

const { override,addLessLoader  } = require('customize-cra');

//更改打包是图片加载模式,解决electron打包后图片无法加载问题
const customizeImageLoader  = () => config  => {  
    config.module.rules[2].oneOf.push({
        test:  [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
        loader: 'file-loader'
    });
    return config;
}
module.exports = override(
    customizeImageLoader()
);

这种方法的缺点是:
多安装了两个模块:react-app-rewired和customize-cra
相较于 npm run eject 暴露配置文件的方法,这种方法不具有透明度的,后面维护的难度较大,

参考资料:
React-CRA 多页面配置(npm run eject)
customize-cra API说明

    原文作者:ZJane
    原文地址: https://segmentfault.com/a/1190000020229885
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞