URIError: Failed to decode param '/%PUBLIC_URL%/favicon.ico' - node.js

I am new to webpack and I got the babel loader and css loader to work and project compiles successfully but when I try to access via browser I get the below error. It looks as if PUBLIC_URL is not recognized. I believe I don't know how to configure this.
I appreciate your valuable comments.
Thanks
ℹ 「wdm」: Compiled successfully. URIError: Failed to decode param
'/%PUBLIC_URL%/favicon.ico' at decodeURIComponent (<anonymous>) at
decode_param (/home/mike/finance-
grapher/node_modules/express/lib/router/layer.js:172:12) at Layer.match
(/home/mike/finance-
grapher/node_modules/express/lib/router/layer.js:123:27) at matchLayer
(/home/mike/finance-
grapher/node_modules/express/lib/router/index.js:574:18) at next
(/home/mike/finance-
grapher/node_modules/express/lib/router/index.js:220:15) at expressInit
(/home/mike/finance-
grapher/node_modules/express/lib/middleware/init.js:40:5) at Layer.handle
[as handle_request] (/home/mike/finance-
grapher/node_modules/express/lib/router/layer.js:95:5) at trim_prefix
(/home/mike/finance-
grapher/node_modules/express/lib/router/index.js:317:13) at
/home/mike/finance-grapher/node_modules/express/lib/router/index.js:284:7
at Function.process_params (/home/mike/finance-
grapher/node_modules/express/lib/router/index.js:335:12)
Webpack.config.js
.babelrc
package.json
project folder structure

Quick fix
What if you were to replace %PUBLIC_URL% with the actual path. I think that Babel is having issues transpiling the %. Try replacing %PUBLIC_URL%/favicon.ico with /public/favicon.ico and the issue is resolved.
Better fix
Add a new rule to your webpack.config.js.
//...
{
test: /\.(png|svg|jpg|jpeg|gif|ico)$/,
exclude: /node_modules/,
use: ['file-loader?name=[name].[ext]'] // ?name=[name].[ext] is only necessary to preserve the original file name
}
//...
Then have the .ico resource copied to the dist directory by adding an import in your App.js. import '../public/favicon.ico';
In your index.html; <link rel="shortcut icon" href="favicon.ico"> to make use of your icon. No longer need to provide a path since it will be copied to the dist directory
OR:
In addition to the rule added to the webpack.config.js mentioned above, adding plugins to the webpack config may be a better way to go depending on your setup.
For me this looks like adding the npm package html-webpack-plugin to the project. Then requiring it in the webpack config; const HtmlWebpackPlugin = require('html-webpack-plugin');. Then adding plugins to the module.exports.
//...
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: './index.html',
favicon: './public/favicon.ico'
})
]
//...
Going this route and doing the work in the webpack config means the line added to the App.js to import the favicon.ico will no longer be necessary.
EDIT: As mentioned by #Tolumide
Don't forget to configure the webpack.config appropriately per environment.

I had the same issue and fixed it with the following:
Inside webpack.config.js in the plugins array, add HtmlWebpackPlugin and InterpolateHtmlPlugin
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw)
This is the documentation of InterpolateHtmlPlugin
Makes some environment variables available in index.html.
The public URL is available as %PUBLIC_URL% in index.html, e.g.:
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
In production, it will be an empty string unless you specify "homepage"
in `package.json`, in which case it will be the pathname of that URL.
In development, this will be an empty string.

Problem fixed
step 1)
remove %PUBLIC_URL% with the actual path. %PUBLIC_URL%/favicon.ico with favicon.ico
Before <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
After <link rel="icon" href="favicon.ico" />
step 2) add this rule to the webpack.config.js
plugins: [new HtmlWebpackPlugin({ template: path.resolve(__dirname, "public", "index.html"),
favicon: "./public/favicon.ico",
filename: "index.html",
manifest: "./public/manifest.json",
})]
step 3) add svg support in webpack(important)
install svg-url-loader package
{
test: /\.svg$/,
use: [
{
loader: 'svg-url-loader',
options: {
limit: 10000,
},
},
],
}

Solution
npm install interpolate-html-plugin --save-dev
Add to list of plugins in webpack config
new InterpolateHtmlPlugin({PUBLIC_URL: 'static })

<link href="<%= htmlWebpackPlugin.options.favicon %>" rel="shortcut icon">
and
new HtmlWebpackPlugin({
favicon: "image/favicon.ico",
})
and
{
test: /\.(jpe?g|gif|png|ico)$/,
use: ['file-loader?name=[name].[ext]']
},

I was getting this error from create-react-app when I was serving the page from express server. It was because I was serving static pages from public folder instead of build folder.
Not working:
app.use('/', express.static(path.join(__dirname, '../public')));
Working
app.use('/', express.static(path.join(__dirname, '../build')));

Installing HtmlWebpackPlugin then import the plugin into webpack.config.js and add this into plugins section worked for me.
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
filename: './index.html',
favicon: './public/favicon.png'
}),
]

Related

webpack multiple output path, limit public access, or custom index.html?

I am using node-express, with typescript.
my folder is setup as follows:
.dist
public
public.js
index.html
server.js
node_modules
src
classes
namespace1
module1
public
app - all angular files.
main.ts
routes
index.ts
app.ts
package.json
tsconfig.json
webpack.config.js
Now, I need webpack to output 2 files to /public/public.js and /server.js at .dist folder. nodejs will then run from .dist/server.js, and I want to separate public.js to prevent client to access server.js
I also use html-webpack-plugin to generate html files.
I have tried using a little hack like
entry: {
"server": "./src/app.ts",
"public/public": "./src/public/main.ts"
}
but then html-webpack-plugin made index.html to load script from /public/public.js instead of public.js
Now, I think we can solve this in 3 way.
Let server.js send public.js using http://localhost/public.js, but it will make managing static folder a little bit complicated. but I will think some way to trick it. Question: how to serve public.js via server.js?
Set entry to "public": "./src/public/main.ts". Question: how to put that public.js into public folder?
Setup html-webpack-plugin to load from /public.js instead of /public/public.js and make index.html inside /public folder. As of now, html-webpack-plugin generates <script type="text/javascript" src="../public/polyfill.js"></script><script type="text/javascript" src="../public/public.js"></script></body> where is should make <script type="text/javascript" src="/polyfill.js"></script><script type="text/javascript" src="/public.js"></script></body>
Question: How to do that?
Or is there any other idea to solve this? I am open to any suggestion.
Thank you
I think I can answer scenarios 2 and 3.
2- Apart of setting up entry points, you can set up some output configuration. http://webpack.github.io/docs/configuration.html#output
3- Also you could use copy webpack plugin to copy the files you need into your public folder.
https://github.com/kevlened/copy-webpack-plugin
I do it in one of my projects, this is the code that I add on the webpack config file:
new CopyWebpackPlugin([
{from: __dirname + '/src/public'}
])
Hope this helps.
Regards.
I managed by using this config.
module.exports = [
{
entry: "./src/app.ts",
output: {
filename: "server.js",
path: __dirname + "/dist"
},
target: "node",
resolve: {
extensions: ['.ts', '.js', '.tsx', '.jsx']
},
node: {
__dirname: false
},
module: { // all modules here for server
}
}, {
entry: "./src/public/main.ts",
output: {
filename: "bundle.js",
path: __dirname + "/dist/public"
},
target: "web",
plugins: [
new htmlPlugin({
filename: 'index.html'
})
],
resolve: {
extensions: ['.ts', '.js', '.tsx', '.jsx']
},
module: { // all your modules here.
}
}
]

"You may need an appropriate loader for this file type", webpack can't parse angular2 file

I'm trying to get a very simple Angular2 app working, with Webpack as a module bundler. I'm following this code, and I copied all the configuration files as they are, only changing file paths. However, when I run npm-start, I get the following error, which I think is a Webpack error:
ERROR in ./hello.js
Module parse failed: /home/marieficid/Documentos/cloud/cloud/hello.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| import {bootstrap} from "angular2/platform/browser";
| import {Component} from "angular2/core";
|
# ./app.ts 2:0-21
As a result, the Angular2 code in my app isn't loaded.
This is my app.ts:
import "./hello.js";
This is hello.js, where the error seems to be (which I take to mean that webpack parsed app.ts just fine):
import {bootstrap} from "angular2/platform/browser";
import {Component} from "angular2/core";
#Component({
selector: 'app',
template: '<div>Hello world</div>'
})
class App{}
bootstrap(App);
And this iswebpack.config.js:
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
module.exports = {
entry: {
'app': './app.ts',
'vendor': './vendor.ts'
},
output: {
path: "./dist",
filename: "bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'),
new HtmlWebpackPlugin({
inject: false,
template: './index.html'
})
],
resolve: {
extensions: ['', '.ts', '.js']
},
module: {
loaders: [
{ test: /\.ts$/, loader: 'ts-loader' },
],
noParse: [ path.join(__dirname, 'node_modules', 'angular2', 'bundles') ]
},
devServer: {
historyApiFallback: true
}
};
All these files and node_modules are in the same directory.
I have found similar questions online but nothing worked for me. I also didn't install babel because the sample code I'm using as base doesn't use it, but if it's necessary I'm will.
As suggested by #napstablook
Since in your webpack.config.js file you have
resolve: {
extensions: ['', '.ts', '.js']
},
Webpack will try to handle those .js files but it needs a specific loader to do so which is, if I'm not wrong, script-loader.
In your case the solution is as simple as deleting the .js files, or changing their extension to be .ts.
For me this issue occurred when I ran ng test,
please check below points,
Console will list out the files that is causing the error.
Check the html file is correctly mapped from the typescript.
styleUrls file should point to the CSS file not html, this is the mistake I
did.
this error also comes up for me in angular forms when i had patch value set then an extra = sign
ncont.controls[position].patchValue({[cardname]:file}) = file
which is a dumb part on me and angular for not telling me

Webpack with a client/server node setup?

I'm trying to set up a webpack-based flow for an Angular2 app with a node backend server. After many hours banging my head against it, I've managed to get the client to build happily, but I can not figure out how to now integrate my server build. My server uses generators, so must target ES6, and it needs to point to a different typings file (main.d.ts instead of browser.d.ts)..
My source tree looks like;
/
-- client/
-- -- <all my angular2 bits> (*.ts)
-- server/
-- -- <all my node/express bits> (*.ts)
-- webpack.config.js
-- typings/
-- -- browser.d.ts
-- -- main.d.ts
I thought perhaps just a tsconfig.json in the client and server folders would work, but no luck there. I also can't find a way to get html-webpack-plugin to ignore my server bundle and not inject it into index.html. My current tsconfig and webpack are below, but has anyone succeeded in getting webpack to bundle a setup like this? Any pointers would be much appreciated.
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"declaration": false,
"removeComments": true,
"noEmitHelpers": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"files": [
"typings/browser.d.ts",
"client/app.ts",
"client/bootstrap.ts",
"client/polyfills.ts"
]
}
and my webpack.config.js;
var Webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var Path = require('path');
module.exports = {
entry: {
'polyfills': Path.join(__dirname, 'client', 'polyfills.ts'),
'client': Path.join(__dirname, 'client', 'bootstrap.ts')
},
output: {
path: Path.join(__dirname, 'dist'),
filename: '[name].bundle.js'
},
resolve: {
extensions: ['', '.js', '.json', '.ts']
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'ts-loader',
query: {
ignoreDiagnostics: [
2403, // 2403 -> Subsequent variable declarations
2300, // 2300 -> Duplicate identifier
2374, // 2374 -> Duplicate number index signature
2375, // 2375 -> Duplicate string index signature
]
}
},
{ test: /\.json$/, loader: 'raw' },
{ test: /\.html$/, loader: 'raw' },
{ test: /\.css$/, loader: 'raw!postcss' },
{ test: /\.less$/, loSWE: 'raw!postcss!less' }
]
},
plugins: [
new HtmlWebpackPlugin({ template: 'client/index.html', filename: 'index.html' }),
new Webpack.optimize.CommonsChunkPlugin('common', 'common.bundle.js')
]
};
Personally, I tend to write my server side code in plain JS (with most of ES2015 available now in Node) and my Angular 2 app in Typescript, so this issue doesn't come up. However, you can get this to work with Webpack.
First, you should have two separate Webpack configs: one for your client-side code and one for the server side. It might be possible to do it with one config, but even if it were, it would likely be more trouble than it's worth. Make sure to set target: 'node' in your server-side config (target: 'web' is set automatically for the client side). And make sure you set an entry point for your server-side files (I don't see one above, but you will ultimately have this in a separate config anyway).
Second, you need to have multiple tsconfig files. By default, ts-loader will look for tsconfig.json in your root directory. However, you can tell specify another file by setting configFileName: 'path/to/tsconfig' in the options object or query string/object.
This may lead to another problem however. Your IDE will also look for your tsconfig.json file in your root directory. If you have two separate files, you will need some way to tell your IDE which one to use for any given file. The solution to this will depend on your IDE. Personally, I use Atom with atom-typescript, which is fantastic, but it looks like the multiple tsconfig files thing is still being worked on. Thankfully I have never had to worry about this problem.
As for the html-webpack-plugin issue, you won't have to worry about it since you won't include the plugin in your server-side config. However, just for reference, you can pass excludeChunks: ['someChunkName'] to omit certain chunks from being included in the script tags.

Should requirejs be included in the main built file when using the requirejs bundles option

I'm running into an issue when using the require bundles option. If the main built file has requirejs inside of it everything works fine until I try to load a file from a different bundle. The bundled file is retrieved but then throws an "define is undefined" error. The only way I have been able to get the bundle to load is to make sure requirejs is not in the main-built file or the pm.js and then to load requirejs with a script tag and use the data-main attribute, but this doesn't seem right.
So something like this initially works when requirejs is included in main-built.js (site loads fine), but I get the "define is undefined" error when pm.js bundle loads
<script type="text/javascript" src="~/dist/main-built.js"></script>
requirejs.config({
bundles: {
'pm': ['pm/dashboard', 'text!pm/dashboard.html']
}
});
This is how I ended up getting it to work, but doesn't seem right.
<script type="text/javascript" src="~/scripts/require.js" data-main="dist/main-debug")"></script>
This durandal task creates the main-built file
durandal: {
main: {
src: ["app/**/*.*", "scripts/durandal/**/*.*", "!app/mockup/**/*.*", "!app/performancemanagement/**/*.*"],
options: {
//name: "scripts/require",
name: "",
baseUrl: requireConfig.baseUrl,
paths: mixIn({}, requireConfig.paths, { "require": "scripts/require.js" }),
exclude: ["jquery", "knockout", "toastr", "moment", "underscore", "amplify"],
optimize: "none",
out: "dist/main-debug.js"
}
},
},
This task builds the pm.js bundle
requirejs: {
compile: {
options: {
include: generateFileList("app/pm", "**/*.*", false, false),
//exclude: ["jquery", "knockout", "toastr", "moment", "underscore", "amplify", "preferenceconstants", "constants", "config", "utility/koutilities", "scripts/logger", "base/viewmodel"]
// .concat(generateFileList("scripts/durandal", "**/*.js", false))
// .concat(generateFileList("app/dataservice", "**/*.js", false))
// .concat(generateFileList("app/model", "**/*.js", false))
// .concat(generateFileList("app/reports", "**/*.js", false)),
baseUrl: "app/",
name: "",
paths: mixIn({}, requireConfig.paths, { "almond": "scripts/almond-custom.js" }),
optimize: 'none',
inlineText: true,
pragmas: {
build: true
},
stubModules: ['text'],
out: "dist/pm.js"
}
}
}
The pm.js bundle gets downloaded and executed when anything in main-built requires it, right now its being done by the router in Durandal, but I'm pretty sure Durandal has nothing to do with the issue.
This appears suspicious in your main file build:
paths: mixIn({}, requireConfig.paths, { "require": "scripts/require.js" }),
I'm not sure what the mixIn bit does as this is not stock RequireJS code, but you seem to want to include RequireJS in the build under the name require, which is definitely wrong. The documentation says:
If you want to include require.js with the main.js source, you can use this kind of command:
node ../../r.js -o baseUrl=. paths.requireLib=../../require name=main include=requireLib out=main-built.js
Since "require" is a reserved dependency name, you create a "requireLib" dependency and map it to the require.js file.

RequireJS baseUrl and multiple optimized files

I've separated out my 3rd party libraries from my app code and grouped them all together into a vendor.js file for requirejs to pull in. In my build.js file, I'm using the modules syntax to optimize my main application, excluding the vendor scripts, and to optimize the vendor.js file. The only issue I'm having is when my compiled main module requests vendor, it's getting the baseUrl from the config file and so doesn't load the optimized vendor.js file. My build.js file looks like this:
({
baseUrl: "js",
dir: "build",
mainConfigFile: "js/main.js",
removeCombined: true,
findNestedDependencies: true,
skipDirOptimize: true,
inlineText: true,
useStrict: true,
wrap: true,
keepBuildDir: false,
optimize: "uglify2",
modules: [
{
name: "vendor"
},
{
name: "main",
exclude: ["vendor"]
}
]
})
And my main.js file looks like this:
requirejs.config({
baseUrl: "js",
paths: {
jquery: 'vendor/jquery/jquery-2.1.3.min',
bootstrap: 'vendor/bootstrap/bootstrap.min',
handlebars: 'vendor/handlebars/handlebars-v2.0.0',
backbone: 'vendor/backbone/backbone-min',
underscore: 'vendor/lodash/lodash.underscore',
marionette: 'vendor/marionette/backbone.marionette.min',
models: 'common/models',
collections: 'common/collections'
}
});
define(['module', 'vendor'], function(module) {
var configPath = "config/config." + module.config().env;
require([configPath, 'app', 'jquery'], function(config, Application, $) {
$(function() {
// Kick off the app
Application.start(config);
});
});
});
All development is done in the js folder, and my build.js file is outside that folder. The optimized files end up in build, a sibling to js, but when I include my main file like this:
<script data-main="build/main" src="js/vendor/require/require.max.js"></script>
It ends up loading js/vendor.js for that define() call. What am I missing here? How can I tell the optimized main file to load build/vendor.js instead, yet allow the unoptimized version to still load js/vendor.js?
Ok, I figured this out. It was simple, really, just a case of too much configuration. When you load your script using data-main, the baseUrl is set relative to that file. So, if I specified js/main, the baseUrl would be js. But, since I explicitly specified baseUrl in the config block of main.js, that gets overridden, both in development and production. By removing baseUrl: "js" from main.js, everything works as expected. The development build loads everything relative to js and the production build loads everything (vendor.js) relative to build when I change data-main to build/main. Hope this helps somebody else someday.
requirejs.config({
paths: {
jquery: 'vendor/jquery/jquery-2.1.3.min',
...
}
});
// 'vendor' is loaded relative to whatever directory main.js is in
define(['module', 'vendor'], function(module) {
...
});

Resources