更改webpack为导入的图像生成的图像的域

时间:2019-09-28 05:18:35

标签: javascript webpack

尽管我的开发服务器正在localhost:3000上运行,但是我已经设置了主机文件以将www.mysite.com指向本地主机。在我的JavaScript中,我有如下代码:

import myImage from '../assets/my-image.jpg'

const MyCmp => <img src={myImage} />

使用Webpack的file-loader,它将导入的URL转换为托管图像的URL。但是,它使用该图像的localhost路径,但是我希望它使用www.mysite.com域。我查看了file-loader的两个publicPath and postTransformPublicPath选项,但是这些选项似乎只允许您修改域 之后的部分路径。

2 个答案:

答案 0 :(得分:1)

我个人不喜欢在构建输出中静态定义主机信息的概念。这是应该在运行时根据实际放置文件的位置来确定的。

如果您像我一样,那么这里有两个选择。 两者都涉及您调用已在即window / global范围内定义的全局方法。 全局方法的目的是在运行时解析根路径(域等)。

定义全局方法

因此,可以说您在启动代码中某处的全局范围内定义了一个方法,如下所示:

(<any>window).getWebpackBundleRootPath = function (webpackLibraryId) {
   if (webpackLibraryId == null) return throw "OOOPS DO SOMETHING HERE!";

   // Preferably these variables should be loaded from a config-file of sorts.
   if(webpackLibraryId == "yourwebpacklibrary1") return "https://www.yoursite.com/";
   // If you have other libraries that are hosted somewhere else, put them here...

   return "...some default path for all other libraries...";
};

下一步是将webpack配置为在尝试解析路径时调用此全局方法。 正如我所提到的,有两种方法,一种用于操纵Webpack的输出,另一种则更多地集成在Webpacks配置中(尽管仅适用于文件加载器,但我认为它就足够了)。

值得一提的是,如果只有一个捆绑软件或将所有捆绑软件托管在一个地方,则不需要全局方法。那么使用一个全局变量就足够了。修改下面的示例以适应这一点应该很容易。

第一个选择:配置webpack文件加载器以在解析路径时调用您的方法

此解决方案在构建后不需要执行任何操作。如果这适合您的需求并涵盖所有情况,那么我会选择此选项。

编辑您的Webpack配置文件

var path = require('path');

let config = {
    entry: {
        'index': path.join(__dirname, '/public/index.js')
    },
    output: {
        path: path.join(__dirname, '/dist/'),
        filename: 'index-bundle.js',
        publicPath: 'https://localhost:3000/',
        library: 'yourwebpacklibrary1',
        ...
    },
    module: {
        rules: [{
            // Please note that this only defines the resolve behavior for ttf. If you want to resolve other files you need to configure the postTransformPublicPath for those too. This is a big caveat in my opinion and might be a reason for using second option.
            test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
            use: [{
                loader: 'file-loader',
                options: {
                    outputPath: 'assets/fonts', // The folder where you store your fonts.
                    name: '[name].[ext]',
                    // This is where the magic happens. This lets you override the output of webpack file resolves.
                    postTransformPublicPath: function (p) {

                        // Because of the way webpack file-loader works the input from to this method will look something like this: __webpack_public_path__ + "/assets/fonts/yourfont.ttf"
                        // But we are not interested in using the __webpack_public_path__ variable so lets remove that.
                        p = p.replace('__webpack_public_path__ + ', '');

                        // Return a stringified call to our global method and append the relative path to the root path returned.
                        return `getWebpackBundleRootPath("${config.output.library}") + ${p}`;
                    }
                }
            }]
        },
    },
    ...
};

module.exports = config;

您可能已经在webpack配置文件的注释中注意到了,您需要为添加的每个文件加载器指定解析行为(如果有人知道更好的方法,请告诉我)。这就是为什么我仍然使用第二个选项的原因。

第二个选项:在构建后的步骤中操作Webpack的输出

示例webpack.config.js文件

为完整起见,这里是一个webpack.config.js文件的示例,其中包含在postbuild脚本中使用的变量。

var path = require('path');

module.exports = {
    entry: {
        'index': path.join(__dirname, '/public/index.js')
    },
    output: {
        path: path.join(__dirname, '/dist/'),
        filename: 'index-bundle.js',
        publicPath: 'https://localhost:3000/',
        library: 'yourwebpacklibrary1',
        ...
    },
    ...
}

创建一个postbuild.js文件

在package.json旁边创建具有以下内容的文件postbuild.js:

const fs = require('fs');

// We take the path to the webpack config file as input so that we can read settings from it.
const webpackConfigFile = process.argv[2];

// Read the webpack config file into memory.
const config = require(webpackConfigFile);

// The file to manipulate is the output javascript bundle that webpack produces.
const inputFile = config.output.path + config.output.filename;

// Load the file into memory.
let fileContent = fs.readFileSync(inputFile, 'utf8');

// Replace the default public path with the call to the method. Please note that if you specify a publicPath as '/' or something very common you might end up with a problem so make sure it is unique in the file to avoid other unrelated stuff being replaced as well.
fileContent = fileContent.replace('"' + config.output.publicPath + '"', 'getWebpackBundleRootPath("' + config.output.library + '")');

// Save the manipulated file back to disk.
fs.writeFileSync(inputFile, fileContent, 'utf8');

在构建时自动调用postbuild.js

下一步是在每次构建后实际调用postbuild.js脚本。 可以在package.json的post script 中完成,就像这样(在package.json的script部分):

{
    "scripts": {
        "build": "webpack",
        "postbuild": "node postbuild.js ./webpack.config.js"
    }
}

从现在开始,无论何时运行构建脚本,它还将运行后构建脚本(从npm或yarn等)。

当然,您也可以在每次构建后手动手动运行postbuild.js脚本。

答案 1 :(得分:0)

  

但这些内容似乎仅允许您修改路径后面的域部分。

并非如此,您可以给它提供一个包含域的URL。

以您为例,假设您的图片位于assets目录下,则webpack.config.js中将有类似的内容

...
module: {
  rules: [
    ...
    {
      test: /\.(png|jpe?g|gif|svg)$/,
      use: {
        loader: 'file-loader',
        options: {
          publicPath: 'https://www.example.com/assets',
          outputPath: 'assets'
        }
      }
    },
    ...
  ]
}
...