如何在Webpack配置中使用__webpack_public_path__变量?

18
我正在使用React、TypeScript和Webpack开发Web应用程序。我希望Webpack根据我只在运行时而不是编译时知道的子域生成图像URL。
我在Webpack文档中读到了这个: http://webpack.github.io/docs/configuration.html#output-publicpath 引用如下: 注意:如果输出文件的最终publicPath在编译时未知,可以将其留空,并在入口点文件中动态设置。如果在编译时不知道publicPath,可以省略它并在入口点上设置webpack_public_path。 webpack_public_path = myRuntimePublicPath // 其余应用程序入口
但我无法让它工作。我已经在我的应用程序入口点设置了webpack_public_path变量。但是我如何在我的Webpack配置中使用它的值? 我需要在这里使用它:

答复

"module": { "rules": [ { "test": /.(png|jpg|gif)(\?[\s\S]+)?$/, "loaders": [url?limit=8192&name=/images/[hash].[ext]] } ] }

我需要做类似于这样的事情:

"loaders": ['url?limit=8192&name=__webpack_public_path__/images/[hash].[ext]']

答案

我已经成功让它工作了。所以在我的入口文件(start.tsx)中,我在导入之前声明了 __webpack_public_path__ 的自由变量,并在导入之后分配了它的值。

/// <reference path="./definitions/definitions.d.ts" />
declare let __webpack_public_path__;

import './styles/main.scss';

/* tslint:disable:no-unused-variable */
import * as React from 'react';
/* tslint:enable:no-unused-variable */
import * as ReactDOM from 'react-dom';
import * as Redux from 'redux';
import { Root } from './components/root';

__webpack_public_path__ = `/xxxx/dist/`;

现在,当我有一个img标签时,公共路径正在被使用:
<img src={require('../../images/logo.png')} />

转化为:

变成:

<img src='/xxxx/dist/images/125665qsd64134fqsf.png')} />
3个回答

14

以下是生成的HTML的基本设置:

<script>
    window.resourceBaseUrl = 'server-generated-path';
</script>
<script src="path-to-bundle" charset="utf-8"></script>

我的主要入口脚本:

__webpack_public_path__ = window.resourceBaseUrl;

谢谢你的回答。我有类似的问题,但由于使用了TypeScript而出现了问题。我将编辑我的问题并更新代码。 - Aiso
由于某些原因,它对我似乎不起作用。使用React和ES6。 - Sagiv b.g
如果你在使用ES6时遇到问题,请按照https://webpack.js.org/guides/public-path/#on-the-fly中的说明进行操作。这对我很有效。 - Zach
我猜你的bundle也作为资源放在服务器上,位于baseUrl路径下,那么你如何使用server-generated-path使path-to-bundle动态化呢? - gotson
我正在尝试理解__webpack_public_path__的上下文。这是一个全局变量,Webpack是否已经定义了它? - Patrick Michaelsen

0
在我的情况下,问题出在我加载脚本的顺序上,在我的 index.html 中要确保最后一个 <script> 标签有一个 src 属性。
我通过阅读生成的 webpack 代码发现了这一点:
var scriptUrl;
if (__webpack_require__.g.importScripts) scriptUrl = __webpack_require__.g.location + "";
var document = __webpack_require__.g.document;
if (!scriptUrl && document) {
    if (document.currentScript)
        scriptUrl = document.currentScript.src
    if (!scriptUrl) {
        var scripts = document.getElementsByTagName("script");
        if(scripts.length) scriptUrl = scripts[scripts.length - 1].src
    }
}
// When supporting browsers where an automatic publicPath is not supported you must specify an output.publicPath manually via configuration
// or pass an empty string ("") and set the __webpack_public_path__ variable from your code to use your own logic.
if (!scriptUrl) throw new Error("Automatic publicPath is not supported in this browser");
scriptUrl = scriptUrl.replace(/#.*$/, "").replace(/\?.*$/, "").replace(/\/[^\/]+$/, "/");
__webpack_require__.p = scriptUrl;

它只是浏览您的脚本并选择最后一个设置为scriptUrl,然后使用它来确定是否使用“publicPath”。由于我的最后一个脚本没有src属性,因此所有对__webpack_public_path__或webpack.config.js { ..., output: { publicPath: "" }}的更改都被忽略了。

我的原始index.html

      <body>
        <div id="root">
          ${html}
        </div>
        
        <script src="/static/runtime.js" type="module"></script>
        <script src="/static/polyfills.js" type="module"></script>
        <script src="/static/vendor.js" type="module"></script>
        <!-- the below is the offending script -->
        <script>
          // WARNING: See the following for security issues around embedding JSON in HTML:
          // https://redux.js.org/usage/server-rendering#security-considerations
          window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
            /</g,
            '\\u003c'
          )}
        </script>
      </body>


我在修改后的index.html

      <body>
        <div id="root">
          ${html}
        </div>
        <script>
          // WARNING: See the following for security issues around embedding JSON in HTML:
          // https://redux.js.org/usage/server-rendering#security-considerations
          window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
            /</g,
            '\\u003c'
          )}
        </script>
        <script src="/static/runtime.js" type="module"></script>
        <script src="/static/polyfills.js" type="module"></script>
        <script src="/static/vendor.js" type="module"></script>
      </body>

这花了我几天时间来修复。


-1

虽然我不是webpack专家,但我不确定你是否正确使用了那个加载器。url-loader的作用是帮助您加载在代码中所需/导入的文件数据。

因此,如果您在入口点中编写了类似以下内容的代码:

var imageData = require("path/to/my/file/file.png");

Webpack会发现你正在尝试导入的不是一个.js文件,然后会在你配置的加载器列表中搜索,看是否可以使用任何加载器来加载该资源。

由于你设置了一个具有与所需资源类型(扩展名.png)匹配的“测试”属性的加载器,它将使用该配置的加载器(url-loader)尝试将该资源加载到你的捆绑包中。

你还可以通过在require路径中添加加载器(以及一些查询字符串,如果你愿意)来告诉webpack他需要使用哪个加载器:

var imageData = require("url-loader?mimetype=image/png!path/to/my/file/file.png");

另外,我不确定是否有一个可以传递给url-loadername参数。

感谢你的回答。name参数是存在的,我们正在使用它,因为我们之前遇到了文件生成到错误文件夹的问题。我已经成功解决了,将会在我的帖子中更新答案。 - Aiso
很高兴你来了,我很好奇看到你的更新帖子。 - Héctor
使用 importrequire 加载资源有什么区别吗? - elQueFaltaba

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接