I have this conundrum I can't solve after many tryouts:
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
file-loader: 1.1.11
url-loader: 1.1.2
AngularJS: 1.6.9
My index.html contains this line and webpack won't load without
<base href="/"></base>
while my AngularJS config block contains
$locationProvider.hashPrefix('');
I use an URL like http://localhost:3000/#/appName/listingComponent/users
and I'm able to see every image using the ng-src (sometimes it's dynamically binded) like this
<img ng-src="app/images/image1.png">
the folder structure is like this
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
In my webpack-dist.js I have the following
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'])
}
};
The build process adds the /customer_company_name/our_company_name/
prefix to the path, which becomes
http://<customer_domain>:<domain_port>/customer_company_name/our_company_name/#/appName/listingComponent/users
while the folder structure is like this
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)
while the request should be made like this
GET http://<customer_domain>:<domain_port>/customer_company_name/our_company_name/index.js
like every other file in the application does.
So far nothing of the following helped:
<base href="/customer_company_name/our_company_name/"></base>
(this is currently retained) require('./images/ODM_trasp48px.png');
(this is currently retained) output.publicPath: '/customer_company_name/our_company_name/'
and also output.publicPath: '/'
options: { useRelativePath: true }
options: { publicPath: /customer_company_name/our_company_name/ }
Can you help me lads, please?
I think the problem is not with the replacement pattern since it works for other file types, but the fact that webpack does not know what to do with ng-src attribute. I think it only looks at the img's src attribute by default. You can change it to recognize ng-src like:
module.exports = {
module: {
loaders: [
...
{
test: /\.html$/,
loaders: [ "html-loader?" + JSON.stringify({ attrs: ["img:src", "img:ng-src"] })]
},
...
],
...
alt syntax:
{
test: /\.html$/,
loaders: [ "html-loader?attrs=img:src img:ng-src" ]
}
Before changing your config, you can just test whether that is the reason by checking if the replacement currently works correctly for img tags with a plain static <img src="..."/>.
Instead of letting webpack parsing your templates, you might try to explicitly import your image(s) and pass it to your template.
The imported images will be then processed by the configured image-loader
or url-loader
.
const myImage = require('./path/to/images/image1.png');
// In component declaration
`<img ng-src="${myImage}">`
Using webpack's 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>
SOLUTION Let's start with
output.publicPath: '/customer_company_name/our_company_name/'
this will take care of rewriting ng-/src paths correctly as explained here .
We won't need the html-loader
to parse ng-/src, the only thing needed is to always use ng-src, or the build won't be successful.
Eventually, there's no need of <base>
tag and neither the initial slash in every path used to refer to images.
I'll update this answer as I improve the webpack-dist.conf.js
/the whole project for the better.
No answer given worked per se, hence I'll try combinations of them since some suggestions look legit.
Eventually, if I won't be able to solve this, I'll try to drop the production path prefix /customer_company_name/our_company_name/
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.