webpack 在电子伪造中不能使用静态文件

cczfrluj  于 2022-11-13  发布在  Webpack
关注(0)|答案(5)|浏览(183)

我有麻烦的图像加载在电子一致。我使用电子锻造与webpack模板https://www.electronforge.io/templates/webpack-template
我的src目录如下所示:

├── images
│   └── black.png
├── index.css
├── index.html
├── index.js
├── main.js
└── renderer.js

我的HTML代码如下所示:

<img src="images/black.png">

我正在使用copy-webpack-plugin复制images目录。
当在开发(npm run start)中运行时,dev服务器的根目录是.webpack/renderer,因此映像加载。当在生产(npm run package)中运行时,HTML文件从文件系统中打开,因此映像标记尝试访问.webpack/renderer/main_window/images,这是错误的位置,它没有加载。
我通过以下方式使它在开发和生产中发挥作用:

<img src="../images/black.png">

这是一个很笨拙的方法,并且不符合文件在src目录中的存储方式。这应该很简单,但是我已经花了几个小时来尝试解决这个问题,还没有一个真实的的解决方案。
我已经看到了在这些链接中表达的解决方案,但是如果不在路径前面加上“../”,我就无法让它在开发和生产中工作。
https://github.com/electron-userland/electron-forge/issues/1196
https://github.com/electron-userland/electron-forge/issues/941
我可以想出几个办法来解决这个问题:

  1. webpack配置需要通过某种环境变量或标志来了解它是在开发还是在生产中运行,并更改copy-webpack-plugin的“to”路径。
    1.更改要运行的开发服务器,使其根目录为.webpack/renderer/main_window
    我已经看到了将图像导入renderer.js的建议,但我有几千张图像。我应该这样做吗?
import './images/1.png';
import './images/2.png';
import './images/3.png';
// ...
import './images/1000.png';

有没有一种方法可以通过编程导入?

let imageMap = {};
for (let i of Iter.range(1, 1001)) {
  let image = import(`./images/${i}.png`);
  imageMap[i] = image;
}

那么我该如何在HTML中引用它呢?没有DOM编辑代码能做到吗?
我不喜欢将图片导入JavaScript文件并通过webpack加载器运行它们,我只想以一种在开发和生产中都有效的方式引用HTML代码中的静态文件。
我也有一个5 MB的JSON文件,我需要使用fetch()访问。我试图通过加载程序导入这个文件,但构建过程花了5分钟多,我杀了它。
加载静态文件是制作网页的一个基本部分,应该是项目模板的一部分,除非我遗漏了一些超级明显的东西。

vmdwslir

vmdwslir1#

我可以通过在生产环境中运行一个静态Express服务器来解决这个问题,该服务器为renderer目录提供服务。
webpack.renderer.config.js

const path = require('path');
const rules = require('./webpack.rules');
const CopyWebpackPlugin = require('copy-webpack-plugin');

const assets = ['data', 'images'];
const copyPlugins = assets.map(asset => {
  return new CopyWebpackPlugin([
    {
      from: path.resolve(__dirname, 'src', asset),
      to: asset
    }
  ]);
});

module.exports = {
  module: {
    rules: [
      ...rules,
    ],
  },
  plugins: [
    ...copyPlugins,
  ]
};

main.js

import { app, BrowserWindow } from 'electron';
import path from 'path';
import express from 'express';

function isDebug() {
  return process.env.npm_lifecycle_event === 'start';
}

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require('electron-squirrel-startup')) { // eslint-disable-line global-require
  app.quit();
}

const createWindow = () => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    width: 1200,
    height: 740,
  });

  if (isDebug()) {
    // Create the browser window.
    mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY);
    mainWindow.webContents.openDevTools();
  } else {
    const exApp = express();
    exApp.use(express.static(path.resolve(__dirname, '..', 'renderer')));
    const server = exApp.listen(0, () => {
      console.log(`port is ${server.address().port}`);
      mainWindow.loadURL(`http://localhost:${server.address().port}/main_window/`);
    });
  }
};

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);
14ifxucb

14ifxucb2#

我也遇到了在生产中加载静态文件的问题,但我想我找到了解决它的方法。我们可以使用electron-is-dev包来检查应用程序是否在生产中运行,然后我们可以为文件指定不同的路径。对于我的情况,我遇到了加载应用程序图标的问题,下面是解决它的方法:

import isDev from "electron-is-dev";

const createWindow = () => {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    height: 1000,
    width: 1000,
    webPreferences: {
      nodeIntegration: true,
    },
  });

  mainWindow.setIcon(
    isDev
      ? path.join(__dirname, "../../src/assets/app.ico")
      : path.join(__dirname, "./assets/app.ico")
  );
};
0md85ypi

0md85ypi3#

我找到了一种方法...
我使用webpack url-loader,这是我的webpack.renderer.config.js的一部分

{
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          options: {
            limit: 20 * 1024, // 20Kb
            outputPath: 'imgs',
            publicPath: '../imgs',
            name: '[name]-[hash:6].[ext]',
            esModule: false
          }
        }
      }
    ]
  }
}

我只是把outputPath的父路径放在publicPath中,它就能在我的应用程序中工作了!

uttx8gqw

uttx8gqw4#

对于那些不想启动服务器来提供静态资源的人,下面是使用最新版本的electron-forge + typescript + webpack + react来使用静态资源的步骤。
假设您的项目具有以下文件结构:

├── src
|    └── index.ts
|    └── index.html
|    └── App.tsx
|    └── renderer.ts
|    └── assets
|          └── images/a.png, b.png
|          └── fonts/a.ttf, t.ttf
├── forge.config.js
├── webpack.main.config.js
├── webpack.renderer.config.js
├── webpack.plugins.js
├── webpack.rules.js
├── package.json

注意:默认情况下,forge的配置被合并到package.json,我将其精确到一个单独的文件forge.config.js,有关详细信息,请参见here

步骤1.

首先,我们需要在src/index.ts中注册一个协议(这是electron主进程的入口点),我们将此协议称为static,稍后您将需要使用static://作为映像资源的前缀。

import { app, BrowserWindow, session } from 'electron';
import path from 'path';

// ...

app.on('ready', () => {
  // Customize protocol to handle static resource.
  session.defaultSession.protocol.registerFileProtocol('static', (request, callback) => {
    const fileUrl = request.url.replace('static://', '');
    const filePath = path.join(app.getAppPath(), '.webpack/renderer', fileUrl);
    callback(filePath);
  });

  createWindow();
});

步骤2.

然后,在webpack.renderer.config.js中,使用copy-webpack-plugin插件将静态资源从src/assets复制到.webpack/renderer文件夹中

const CopyWebpackPlugin = require('copy-webpack-plugin');
const path = require('path');

const assets = ['assets'];
const copyPlugins = new CopyWebpackPlugin(
  {
    patterns: assets.map((asset) => ({
      from: path.resolve(__dirname, 'src', asset),
      to: path.resolve(__dirname, '.webpack/renderer', asset)
    }))
  }
);

步骤3.

最后,在src/App.tsx中,编写react代码来渲染图像。

import React from 'react'
import * as ReactDOM from 'react-dom/client'

const root = ReactDOM.createRoot(document.getElementById('app'))
root.render(<img src='static://assets/images/a.png'/>)

src/index.html文件中添加id = 'app'的新div

<body>
  <div id="app"></div>
</body>

并且不要忘记在src/renderer.ts中引用它

import './App';

故障排除

如果您遇到Content-Security-Policy问题,请在forge.config.js中输入以下行。

"plugins": [
    [
        "@electron-forge/plugin-webpack",
        {
            "mainConfig": "./webpack.main.config.js",
            "devContentSecurityPolicy": "default-src 'self' 'unsafe-eval' 'unsafe-inline' static: http: https: ws:", // <--- this line
            // ...
        }
    ]
]

要小心unsafe-inline,它可能会导致安全问题,请确保使用安全的源代码,或者在不需要时将其删除。

1aaf6o9v

1aaf6o9v5#

谢谢wanZzz的提示,但我必须通过更改outputPath来进行调整:'/'和publicPath的路径;
我的网络包。规则是

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    use: {
      loader: "url-loader",
      options: {
        limit: 20 * 1024, // 20Kb
        outputPath: "/",
        publicPath: "/src/assets/images",
        name: "[path][name].[ext]",
        esModule: false,
      },
    },
  },

相关问题