Index.html template isn't loading favicon for HtmlWebpackPlugin - javascript

I'm trying to load a favicon using the index.html that is the template for the HtmlWebpackPlugin but it's not loading.
That is how my Webpack config looks like:
'use strict'
const webpack = require('webpack')
const { join, resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: join(__dirname, 'src', 'index'),
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.s?css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
},
resolve: {
extensions: ['.js']
},
devServer: {
contentBase: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: join(__dirname, 'public', 'index.html')
})
]
}
And that is my index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="shortcut icon" href="favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>

HTMLWebpackPlugin will not parse the HTML to find your resources. You'll need to include it like this in your template:
index.html
<link rel="shortcut icon" href="${require('./favicon.ico')}">
You'll also need to include file-loader for your .ico file:
webpack.config.js
{
test: /\.ico$/,
loader: 'file-loader'
}

HtmlWebpackPlugin has an option called favicon which lets you inject an icon link into the header in development or production.
new HtmlWebpackPlugin({
title: "Title Here",
template: "./src/index.html",
favicon: "./src/favicon.ico",
inject: "body",
})
You should also have a rule to grab the icon, and also import it in your bundler file.
// # Target: favicon
{
test: /\.ico$/i,
type: "asset/resource",
// Use 'generator' to output unique name (based on webpack pattern e.g. [name], [ext], etc.)
generator: {
filename: "[name][ext][query]"
}
},
NB: I'm writing for Webpack 5
I'm not sure if Webpack 4 has the type: "asset/resource" feature, but I assume you can achieve the same thing with file-loader and its options.
{
test: /\.ico$/i,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]"
}
}
},
*Not guaranteed for Webpack 4.

Related

Phoenix 1.4 server is delivering default HTML instead of requested JS files

I am trying to render Vue.js directly in my Phoenix 1.4 application. But the following error is occurring after installing Vue-router:
Refused to execute script from 'http://localhost:4000/0.app.js'
because its MIME type ('text/html') is not executable, and strict MIME
type checking is enabled.
My Phoenix router.ex file looks as follows:
scope "/", Web do
pipe_through :browser
get "/*path", PageController, :index
end
My webpack.config.js:
const path = require('path');
const glob = require('glob');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = (env, options) => ({
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
optimization: {
minimizer: [
new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: false }),
new OptimizeCSSAssetsPlugin({})
]
},
entry: {
'./js/app.js': glob.sync('./vendor/**/*.js').concat(['./js/app.js'])
},
output: {
filename: 'app.js',
path: path.resolve(__dirname, '../priv/static/js')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.s(c|a)ss$/,
use: [
'css-loader',
{
loader: 'sass-loader',
// Requires sass-loader#^7.0.0
options: {
implementation: require('sass'),
fiber: require('fibers'),
indentedSyntax: true // optional
}
}
]
},
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, use: 'url-loader' }
]
},
plugins: [
new MiniCssExtractPlugin({ filename: '../css/app.css' }),
new CopyWebpackPlugin([{ from: 'static/', to: '../' }]),
new VueLoaderPlugin()
]
});
I am currently seeing an issue with (I think) the cache manifest whereby my site delivers HTML and CSS files properly but for JS files, the default HTML template is being delivered - which results in an erro.
I can see in the Chrome Dev Tools Network tab that the response from this request http://localhost:4000/0.app.js is the app.html.eex file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Phoenix Framework</title>
</head>
<body>
<div id="vue-app"></div>
<script type="text/javascript" src="<%= Routes.static_path(#conn, "/js/app.js") %>"></script>
</body>
</html>
Any help greatly appreciated.
If you use a wildcard catch-all route to show your index page, and requests to resources are hitting that route, this means that Plug.Static is not set up correctly in your endpoint.ex.
Ours looks something like this:
plug Plug.Static,
at: "/", from: :my_app_name, gzip: true,
only: ~w(css images js favicon.ico robots.txt fonts)
put that anywhere before you do plug MyApp.Router.
Another reason could be that 0.app.js simply doesn't exist in priv/static/js. Check there to see if it isn't actually called app.js or has a hash appended to its name.

How can I build a React app with Webpack and import an assets folder?

My main problem is that I'm trying to build a React Application but the assets folder is missing and I don't know how to import it and configure it in webpack.conf. Another problem is the relative route of index.html: I don't know if it will be affected in the application build.
Thanks in advance.
Application Tree
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>App</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="shortcut icon" href="src/assets/favicon.ico"/>
</head>
<body>
<div id="app"></div>
</body>
</html>
Webpack Config:
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
},
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".jsx", ".json"]
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "awesome-typescript-loader"
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
]
},
plugins: [
new HTMLWebpackPlugin({
template: 'public/index.html'
}),
new MiniCssExtractPlugin("style.css")
],
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
devServer: {
historyApiFallback: true,
port: 3000
}
};
You can use webpack-copy-plugin to copy additional folders / files as part of the build process
new CopyPlugin([{
from: path.resolve(__dirname, 'src', 'assets'),
to: path.resolve(__dirname, 'build', 'assets')
}])
As #James mentioned: "You can use webpack-copy-plugin to copy additional folders / files as part of the build process"
However, there is a small error while using you example #James, it should be like this:
webpack.config.js
plugins: [
//...
new CopyPlugin({
patterns: [
{ from: path.resolve(__dirname, 'src', 'assets'), to: path.resolve(__dirname, 'build', 'assets') },
],
})
],
Hope it helps (upvote james for his help if it helps you too)

webpack-dev-server injects CSS webpack doesn't

I'm new to webpack and I'm facing an issue while trying to build a simple webpage.
While I don't have problems when using webpack-dev-server, when I build my application with webpack I don't see the CSS inside the index.html file.
Here is the webpack.conf.js:
var path = require( "path" );
const HtmlWebpackPlugin = require( 'html-webpack-plugin' );
module.exports = {
entry: {
index: path.join( __dirname, "src", "index.js" )
},
output: {
path: path.join( __dirname, "dist" ),
filename: "bundle.js"
},
devServer: {
host: '0.0.0.0',
port: 9000,
writeToDisk: true
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
exclude: /(node_modules)/,
use: ['file-loader'],
},
{
test: /\.svg$/,
exclude: /(node_modules)/,
loader: 'svg-inline-loader'
},
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: { presets: ["#babel/preset-env"] }
}
},
{
test: /\.styl$/,
exclude: /(node_modules)/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"stylus-loader" // compiles Stylus to CSS
]
}
]
},
plugins: [
new HtmlWebpackPlugin( {
filename: 'index.html',
template: path.join( __dirname, "src", "index.html" ),
inject: true
} ),
]
};
This is the index.js:
import "./css/index.styl";
import "./css/graphics.styl";
import "./js/polyfills.js"
import "./js/manager.js"
console.log( "TEEEEEEEEEEEEEEEEST" );
Here the index.html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport"
content="user-scalable=no, width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
</head>
<body>
<div id="graphicsContainer" class="graphics-container">
<%=require('./assets/images/barca_onde.svg')%>
</div>
</body>
</html>
I run the dev mode with this command:
./node_modules/webpack-dev-server/bin/webpack-dev-server.js --config /app/webpack.config.js --mode development --color --watch
While the build command I use is this:
./node_modules/webpack/bin/webpack.js --config /app/webpack.config.js --mode production --color
Both commands don't show any error, but the first generates the bundle.js, the inline SVG, the CSS code and injects them in the index.html while the second only generates bundle.js and the SVG and injects them in index.html leaving the CSS out.
What am I missing? Thank you in advance!
This is happening because your configuration isn't set up to write your compiled CSS to a file. The injection of style only happens in development mode, which is why you aren't seeing it when you build in production mode.
If you're using the latest major release of webpack (which is 4 as of this answer), you'll want to use MiniCssExtractPlugin. It replaces style-loader in your configuration.
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV === 'development';
// ...
{
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
}),
],
rules: [
{
test: /\.styl$/,
exclude: /(node_modules)/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: { hmr: devMode },
},
"css-loader",
"stylus-loader"
]
}
]
}
For prior major releases of webpack, see ExtractTextWebpackPlugin.

live reload when css is changed

How can i live reload the page when css is changed? Right now when js file is changed, live reload works. The project structure of my project is
output - css(assets/css/main.css) is inside this folder and so index.html
src - all react files
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Kolaboo</title>
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="./assets/css/main.css">
</head>
<body>
<div class="app">
</div>
<script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" type="text/javascript"></script>
<script src="./app.js"></script>
</body>
</html>
webpack.config.js
const path = require('path');
const webpack = require('webpack');
// webpack sets the NODE_ENV when calling it with -p or -d
if (!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development';
}
const webpackConfig = {
cache: true,
entry: './src/index.js',
output: {
path: path.join(__dirname, 'output', 'build'),
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'stage-2']
}
}, // also adds ES6 support
{
test: /\.(png|svg|jpg|jpeg|jpeg|ttf|woff|eot|gif)$/,
loader: 'url-loader?limit=100000'
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
},
{
test: /masonry|imagesloaded|fizzy\-ui\-utils|desandro\-|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
loader: 'imports?define=>false&this=>window'
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
],
resolve: {
root: path.join(__dirname, 'src'),
modulesDirectories: ['node_modules']
},
devServer: {
contentBase: './public',
hot: true,
historyApiFallback: true
},
};
if (process.env.NODE_ENV === 'production') {
webpackConfig.plugins.push(
new webpack.optimize.UglifyJsPlugin()
);
}
module.exports = webpackConfig;
Note: if i place the css file on the same place where js file is and import it using import './main.css', it works but not if i want to include the css file in index.html.

Webpack dev server not serving output

I have an application that's structured like this:
- root
- app/
- config/
- css/
- js/
- public/
- package.json
- webpack.config.js
The React app is in the app folder and I'm publishing to the public folder. Here is my webpack configuration:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var extractSass = new ExtractTextPlugin(
"../css/style.css", {
allChunks: true
});
module.exports = {
context: path.join(__dirname, "public"),
devtool: debug ? "inline-sourcemap" : null,
entry: {
withify: '../app/main.jsx',
fbauth: '../app/fbauth.jsx',
fbuser: '../app/fbuser.jsx',
fontawesome: 'font-awesome-webpack!../node_modules/font-awesome-webpack/font-awesome.config.js',
styles: './css/style.scss'
},
output: {
path: './js',
filename: '[name].js'
},
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV || 'development')
}
},
module: {
loaders: [
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'],
}
},
{
test: /\.scss$/,
loader: extractSass.extract(["css", "sass"])
},
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpg)?(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
loader: 'url'
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
}]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
extractSass
],
externals: {
fs: '{}',
tls: '{}',
net: '{}',
console: '{}'
}
};
Here is how I'm trying to start the app with npm run dev:
"scripts": {
"dev": "./node_modules/.bin/webpack-dev-server --content-base public --inline --hot"
},
However, when my index.html tries to access the withify.js file that should be available in memory in the development server I'm getting a 404; what did I do wrong here?
<html>
<head>
<title>Withify Application</title>
<!-- Mobile Specific Metas ================================================== -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAlPNWOZmv60OUaD3_idHMP15-Ghwm7RDE&libraries=places"></script>
<link type="text/css" rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="app"></div>
<script src="/js/jquery.min.js"></script>
<script src="/js/withify.js"></script>
<script defer src="https://code.getmdl.io/1.1.3/material.min.js"></script>
</body>
</html>
Ok well a couple things:
Context is the folder where you tell webpack where to look for your entries. So currently you are telling webpack to look into the public folder, but all of your entries live in "/app"
So your context would be something like:
context: path.join(_dirname, 'app')
This tells webpack look into root/app and find the entries which should now look like:
entry: [
withify: 'main.jsx',
fbauth: 'fbauth.jsx',
fbuser: 'fbuser.jsx',
]
And your output will be something like this:
output:[
path: path.join(__dirname, 'public', 'js')
filename: '[name].js'
]
I think that should fix your issues as long as you are pulling everything from your public folder!
EDIT:
Try setting this as well in your output:
output:[
path: path.join(__dirname, 'public', 'js'),
filename: '[name].js',
publicPath: '/js/'
]

Categories