diff --git a/config/paths.js b/config/paths.js index 7645917fbc95504483c75679eee42bd417624f93..e6f2ff6cb3a669d5ebe8a6f0a78e352d899ff70c 100644 --- a/config/paths.js +++ b/config/paths.js @@ -36,7 +36,6 @@ if (isInCreateReactAppSource) { module.exports = { appBuild: resolveOwn('../build'), appHtml: resolveOwn('../template/index.html'), - appFavicon: resolveOwn('../template/favicon.ico'), appPackageJson: resolveOwn('../package.json'), appSrc: resolveOwn('../template/src'), appNodeModules: resolveOwn('../node_modules'), @@ -47,7 +46,6 @@ if (isInCreateReactAppSource) { module.exports = { appBuild: resolveApp('build'), appHtml: resolveApp('index.html'), - appFavicon: resolveApp('favicon.ico'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appNodeModules: resolveApp('node_modules'), @@ -59,7 +57,6 @@ if (isInCreateReactAppSource) { module.exports = { appBuild: resolveApp('build'), appHtml: resolveApp('index.html'), - appFavicon: resolveApp('favicon.ico'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), appNodeModules: resolveApp('node_modules'), diff --git a/config/webpack.config.dev.js b/config/webpack.config.dev.js index ae95e0d92b85136481b636a3c7cc33b55886ba38..5e28bb7c916cb5e082422da7efa1f0c1964bf734 100644 --- a/config/webpack.config.dev.js +++ b/config/webpack.config.dev.js @@ -126,13 +126,23 @@ module.exports = { // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. { - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, + test: /\.(ico|jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, include: [paths.appSrc, paths.appNodeModules], + exclude: /\/favicon.ico$/, loader: 'file', query: { name: 'static/media/[name].[ext]' } }, + // A special case for favicon.ico to place it into build root directory. + { + test: /\/favicon.ico$/, + include: [paths.appSrc], + loader: 'file', + query: { + name: 'favicon.ico?[hash:8]' + } + }, // "url" loader works just like "file" loader but it also embeds // assets smaller than specified size as data URLs to avoid requests. { @@ -143,6 +153,15 @@ module.exports = { limit: 10000, name: 'static/media/[name].[ext]' } + }, + // "html" loader is used to process template page (index.html) to resolve + // resources linked with <link href="./relative/path"> HTML tags. + { + test: /\.html$/, + loader: 'html', + query: { + attrs: ['link:href'], + } } ] }, @@ -169,7 +188,6 @@ module.exports = { new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, - favicon: paths.appFavicon, }), // Makes some environment variables available to the JS code, for example: // if (process.env.NODE_ENV === 'development') { ... }. See `env.js`. diff --git a/config/webpack.config.prod.js b/config/webpack.config.prod.js index 66ca7a8cec189a1fdb0c288d8213b5b9fa70179e..ffeb75a9488b41886ca43f2ea6177edb6dd2a66e 100644 --- a/config/webpack.config.prod.js +++ b/config/webpack.config.prod.js @@ -126,23 +126,33 @@ module.exports = { loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss') // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, + // JSON is not enabled by default in Webpack but both Node and Browserify + // allow it implicitly so we also enable it. { - // JSON is not enabled by default in Webpack but both Node and Browserify - // allow it implicitly so we also enable it. test: /\.json$/, include: [paths.appSrc, paths.appNodeModules], loader: 'json' }, + // "file" loader makes sure those assets end up in the `build` folder. + // When you `import` an asset, you get its filename. { - // "file" loader makes sure those assets end up in the `build` folder. - // When you `import` an asset, you get its filename. - test: /\.(jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, + test: /\.(ico|jpg|png|gif|eot|svg|ttf|woff|woff2)(\?.*)?$/, + exclude: /\/favicon.ico$/, include: [paths.appSrc, paths.appNodeModules], loader: 'file', query: { name: 'static/media/[name].[hash:8].[ext]' } }, + // A special case for favicon.ico to place it into build root directory. + { + test: /\/favicon.ico$/, + include: [paths.appSrc], + loader: 'file', + query: { + name: 'favicon.ico?[hash:8]' + } + }, // "url" loader works just like "file" loader but it also embeds // assets smaller than specified size as data URLs to avoid requests. { @@ -153,6 +163,15 @@ module.exports = { limit: 10000, name: 'static/media/[name].[hash:8].[ext]' } + }, + // "html" loader is used to process template page (index.html) to resolve + // resources linked with <link href="./relative/path"> HTML tags. + { + test: /\.html$/, + loader: 'html', + query: { + attrs: ['link:href'], + } } ] }, @@ -181,7 +200,6 @@ module.exports = { new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, - favicon: paths.appFavicon, minify: { removeComments: true, collapseWhitespace: true, diff --git a/package.json b/package.json index 77910fcf3498df86992ecbe1365bc67278a57cf3..1b389da8005e0ba3179ca0902bba0e383f13280d 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "filesize": "3.3.0", "fs-extra": "0.30.0", "gzip-size": "3.0.0", + "html-loader": "0.4.3", "html-webpack-plugin": "2.22.0", "http-proxy-middleware": "0.17.0", "jest": "14.1.0", diff --git a/tasks/e2e.sh b/tasks/e2e.sh index a1566a85bdb903c8878ac9a0c04b43118dc36164..6e6c20c9420319fb05e0337b1d03e55498414d01 100755 --- a/tasks/e2e.sh +++ b/tasks/e2e.sh @@ -67,6 +67,7 @@ test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg +test -e build/favicon.ico # Run tests npm run test @@ -96,6 +97,7 @@ test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg +test -e build/favicon.ico # Run tests npm run test @@ -113,6 +115,7 @@ test -e build/*.html test -e build/static/js/*.js test -e build/static/css/*.css test -e build/static/media/*.svg +test -e build/favicon.ico # Run tests npm run test diff --git a/template/index.html b/template/index.html index 72e10e94c6cc05d7f15f45424fa9b7ed05741fe8..f89671553ebcf7a8e800e08a35d3807bccc762b0 100644 --- a/template/index.html +++ b/template/index.html @@ -3,6 +3,7 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> + <link rel="shortcut icon" href="./src/favicon.ico"> <title>React App</title> </head> <body> diff --git a/template/favicon.ico b/template/src/favicon.ico similarity index 100% rename from template/favicon.ico rename to template/src/favicon.ico