使用 Webpack 和 AngularJS 的图像 GET 在生产中抛出 404 错误

Images GETs throw 404 error in production using Webpack and AngularJS

我有这个难题,试了很多次都解决不了:

I'm unable to load static images in production;

everything is fine while developing (npm run serve), even when serving files from dist (npm run serve:dist)

版本

Webpack: 3.12.0

文件加载器:1.1.11

url-加载程序:1.1.2

AngularJS: 1.6.9

开发中:

我的 index.html 包含这一行,没有

webpack 将无法加载
<base href="/"></base>

而我的 AngularJS 配置块包含

$locationProvider.hashPrefix('');

我用的是URL之类的 http://localhost:3000/#/appName/listingComponent/users

并且我能够使用 ng-src(有时它是动态绑定的)来查看每个图像,就像这样

<img ng-src="app/images/image1.png">

文件夹结构是这样的

ui/
├── conf/
│   ├── browsersync-dist.conf.js
│   ├── browsersync.conf.js
│   ├── gulp.conf.js
│   ├── webpack-dist.conf.js
│   └── webpack.conf.js
├── gulp_tasks/
│   ├── browsersync.js
│   ├── misc.js
│   └── webpack.js
├── node_modules/
├── src/
│   ├── app/
│   │   ├── config.js  //global variables
│   │   ├── favicon.ico
│   │   ├── index.html
│   │   ├── index.js
│   │   ├── index.less
│   │   ├── images/ <--
│   │   ├── actual_app_folders/
│   │   └── ...
├── gulpfile.js
└── package.json

在我的 webpack-dist.js 我有以下内容

module.exports = {
  module: {
    loaders: [
      {
        test: /\.json$/,
        loaders: [
          'json-loader'
        ]
      },
      {
        test: /\.js$/,
        exclude: [
          /node_modules/
        ],
        loader: 'babel-loader',
        options: {
          presets: ['es2015']
        }
      },
      {
        test: /\.js$/,
        exclude: [
          /node_modules/
        ],
        loaders: [
          'eslint-loader'
        ],
        enforce: 'pre'
      },
      {
        test: /\.(css|less)$/,
        exclude: '/node_modules/roboto-fontface/',
        loaders: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader?minimize!less-loader!postcss-loader'
        })
      },
      {
        test: /\.html$/,
        loaders: [
          'html-loader'
        ]
      },
      {
        test: /\.(jpe?g|png|gif|svg|eot|woff|ttf|svg|woff2)$/,
        loader: 'url-loader?name=[name].[ext]'
      }
    ]
  },
  plugins: [
    new webpack.NoEmitOnErrorsPlugin(),
    FailPlugin,
    new HtmlWebpackPlugin({
      template: conf.path.src('/app/index.html'),
      inject: true,
      chunksSortMode: 'dependency'
    }),
    new webpack.optimize.CommonsChunkPlugin({
      name: ['vendors', 'config'],
      minChunks: Infinity
    }),
    new ExtractTextPlugin('index-[contenthash].css'),
    new webpack.LoaderOptionsPlugin({
      options: {
        postcss: () => [autoprefixer]
      }
    })
  ],
  output: {
    path: conf.paths.dist,
    filename: function(output) {
      return output['chunk']['name'] === 'config' ? '[name].js' : '[name]-[hash].js';
    },
    chunkFilename: '[name]-[hash].js'
  },
  entry: {
    app: `./${conf.path.src('/app/index')}`,
    config: `./${conf.path.src('/app/config')}`,
    vendors: Object.keys(pkg.dependencies).concat(['webpack-material-design-icons'])
  }
};

制作中

构建过程在路径中添加/customer_company_name/our_company_name/前缀,变成

http://<customer_domain>:<domain_port>/customer_company_name/our_company_name/#/appName/listingComponent/users

而文件夹结构是这样的

our_company_name/
├── app/
│   ├── images/ <--
│   │   ├── image1.png
│   │   └── image2.png
├── app-<random_number>.js
├── config.js
├── favicon.ico
├── index.html
├── index-<random_number>.css
└── vendors.js

THE PROBLEM

Now every time there's a pic to be shown, the browser gets a 404 error like this

GET http://<customer_domain>:<domain_port>/app/images/image1.png 404 (Not Found)

虽然请求应该像这样

GET http://<customer_domain>:<domain_port>/customer_company_name/our_company_name/index.js

与应用程序中的所有其他文件一样。

我试过的

到目前为止,以下都没有帮助:

  1. 在以下 <base href="/customer_company_name/our_company_name/"></base> 构建过程中更改基础标记(当前保留)
  2. 明确要求 index.js require('./images/ODM_trasp48px.png'); 中的所有其他文件的图片(当前保留)
  3. 在 webpack output.publicPath: '/customer_company_name/our_company_name/' 中使用 publicPath output.publicPath: '/'
  4. 使用 file-loader 而不是 url-loader(目前保留)
  5. 将文件加载器与 options: { useRelativePath: true }
  6. 一起使用
  7. 将文件加载器与 options: { publicPath: /customer_company_name/our_company_name/ }
  8. 一起使用

伙计们,你们能帮帮我吗?

我认为问题不在于替换模式,因为它适用于其他文件类型,而在于 webpack 不知道如何处理 ng-src 属性。我认为默认情况下它只查看 img 的 src 属性。您可以更改它以识别 ng-src,例如:

module.exports = {
  module: {
    loaders: [
    ...
    {
      test: /\.html$/,
      loaders: [ "html-loader?" + JSON.stringify({ attrs: ["img:src", "img:ng-src"] })]
    },
    ...
  ],
   ...

替代语法:

{
   test: /\.html$/,
   loaders: [ "html-loader?attrs=img:src img:ng-src" ]
}

在更改您的配置之前,您可以通过检查替换当前是否适用于具有普通静态 的 img 标签来测试这是否是原因。

您可以尝试显式导入您的图像并将其传递给您的模板,而不是让 webpack 解析您的模板。

导入的图像将由配置的image-loaderurl-loader处理。

静态图片

const myImage = require('./path/to/images/image1.png');

// In component declaration 
`<img ng-src="${myImage}">`

动态图片

使用 webpack 的 require.context

const pathToImages = require.context('./path/to/images', true);
const dynamicImageName = 'foo.jpg',

// In component declaration 
`<img ng-src="${pathToImages(dynamicImageName, true)}">`

你可以试试下面改成你的 index.html

<base href="./"></base>

解决方案 让我们从

开始

output.publicPath: '/customer_company_name/our_company_name/'

这将按照 here 的说明正确重写 ng-/src 路径。

我们不需要 html-loader 来解析 ng-/src,唯一需要的是始终使用 ng-src,否则构建将不会成功。

最终,不再需要 <base> 标记,也不再需要每个路径中用于引用图像的初始斜杠。

我会在改进 webpack-dist.conf.js/整个项目时更新这个答案。


没有给出的答案本身有效,因此我会尝试将它们组合起来,因为有些建议看起来很合理。

最后,如果我无法解决这个问题,我会尝试删除生产路径前缀 /customer_company_name/our_company_name/