What does this single line of webpack html loader syntax mean? - javascript

To solve a problem I was having with my webpack.config.js file I copied a line from a webpack blog. The line is starred in the code below. However I can't seem to easily figure out what the line is doing and googling didn't lead me to a simple explanation. So, what is the purpose/syntax of the indicated line? A short explanation would probably suffice, but a link to some (official) documentation would also be helpful.
var path = require('path');
module.exports = {
entry: {
javascript: ['babel-polyfill', './src/main.js'],
html: './index.html'
},
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js'
},
devtools: 'inline-source-map',
module: {
loaders: [
{
loader: 'babel-loader',
test: path.join(__dirname, 'src'),
query: {
presets: ['react', 'es2015', 'stage-2']
}
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]' // <---- **********
}
]
}
};

The webpack file loader lets you specify a custom filename template for imported files using the name= query parameter:
https://github.com/webpack/file-loader#filename-templates

Webpack 1 supports configuring a loader entirely through a query-string like DSL. Written in the alternative syntax for configuration makes it clear(er) what is going on:
{
test: /\.html$/,
loader: 'file', // Use the file loader
query: { // Configuring it with the following options
name: '[name].[ext]'
// Set the name of the HTML files that are output to be
// the local name of the file, followed by a literal dot character
// followed by the file's extension.
}
}

Related

configure Laravel mix mix.webpackConfig({}) with entry points and outputs

I'm developing an application that use php 5.6 and laravel 5.4. I'm using laravel mix for build my assets. I need to know how to use mix.webpackConfig({}) method to use another webpack configurations like use babel-loader, riot-tag-loader etc. Is there any way to use this method to do that with entry point and output files? For an example, I need to do following thing inside my mix.webpackConfig({}).
module.exports = {
entry: {
admin: ['./resources/assets/admin/js/app.js'],
'manuals/parent/child/js': ['./resources/views/manuals/parent/child/js/app.js']
},
output: {
filename: '[name]/app.js',
path: path.resolve(__dirname + '/public')
},
module: {
rules: [
{
test: /\.tag$/,
exclude: /node_modules/,
loader: 'riot-tag-loader',
query: {
type: 'es6',
hot: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
Is that possible? Is that so, please let me know how to do that. Thanks
I've hardly found the laravel-mix mix.webpackConfig({}) successfully initiated, and even working samples are rear. I do not know what framework you are trying to manage but this sample works; this is a config for less-loader, hope you can tune it to suit your purpose.
const path = require('path');
mix.webpackConfig({
module: {
rules: [
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
exclude: [
path.resolve(__dirname, "node-modules"),
path.resolve(__dirname, "resources/assets/less"),
],
},
]}
})
Mix is a configuration layer on top of Webpack, so to run your Mix tasks you only need to execute one of the NPM scripts that is included with the default Laravel package.json file: more details in official site
https://laravel.com/docs/5.7/mix

Webpack output bundle larger than expected

The only thing I have in my entry JS file is:
import $ from 'jquery';
The jQuery JS file has the size of 29.5kb from jsdelivr.
My entry, that only includes jQuery, and nothing else, has the size of 86kb.
webpack.config.js
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry: './src/js/scripts.js',
output: {
publicPath: "./dist/",
path: path.join(__dirname, "dist/js/"),
filename: "bundle.js"
},
watch: true,
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: [
['env', { loose:true, modules:false }],
'stage-2'
],
plugins: [
['transform-react-jsx', { pragma:'h' }]
]
}
},
{
test: /\.pug$/,
use: [
"file-loader?name=[name].html&outputPath=../dist",
"extract-loader",
"html-loader",
"pug-html-loader"
]
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
use: ['css-loader?url=false', 'sass-loader']
})
},
]
},
resolve: {
alias: {
"TweenMax": path.resolve('node_modules', 'gsap/src/uncompressed/TweenMax.js'),
"TimelineMax": path.resolve('node_modules', 'gsap/src/uncompressed/TimelineMax.js'),
"animation.gsap": path.resolve('node_modules', 'scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js'),
}
},
plugins: [
new ExtractTextPlugin('../css/main.css'),
new UglifyJsPlugin({
test: /\.js($|\?)/i
})
],
stats: {
warnings: false
}
};
I should also mention, that going into the output bundle.js it still has the jQuery comments.
jQuery JavaScript Library v3.3.1
https://jquery.com/ ...
Even though I'm calling webpack with the -p argument and have the UglifyJS plugin, but the rest of the file is minified and mangled. Any ideas?
Thanks!
Try to copy and paste minified jquery from your link. It's has size of 86.9 kb.
This link also show that jquery v3 minified file size is also around 80kb.
So you already have correct setup. Maybe your 29.5kb file size is minified+gzipped file.
The 29.5kb file size is definitely the minified+gzipped version as per the link Niyoko posted.
I would also recommend checking out Fuse-Box It brought down our project size from over 1mb to under 200kb (Vendor and App bundles combined). Very easy to get going as well and it is TypeScript first :) It takes the best features from a number of the more popular bundlers and brings them together and builds on those features.

Typescript: How to have some imports in the global scope?

Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.

Conflict: Multiple assets emit to the same filename

I'm a webpack rookie who wants to learn all about it.
I came across a conflict when running my webpack telling me:
ERROR in chunk html [entry] app.js Conflict: Multiple assets emit to
the same filename app.js
What should I do to avoid the conflict?
This is my webpack.config.js:
module.exports = {
context: __dirname + "/app",
entry: {
'javascript': "./js/app.js",
'html': "./index.html",
},
output: {
path: __dirname + "/dist",
filename: "app.js",
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ["babel-loader"]
},
{
test: /\.html$/,
loader: "file-loader?name=[name].[ext]",
}
]
}
};
i'm not quite familiar with your approach so I'll show you a common way to help you out.
First of all, on your output, you are specifying the filename to app.js which makes sense for me that the output will still be app.js. If you want to make it dynamic, then just use "filename": "[name].js".
The [name] part will make the filename dynamic for you. That's the purpose of your entry as an object. Each key will be used as a name in replacement of the [name].js.
And second, you can use the html-webpack-plugin. You don't need to include it as a test.
I had the same problem, I found it was setting a static output file name that was causing my problem, in the output object try the following object.
output:{
filename: '[name].js',
path: __dirname + '/build',
chunkFilename: '[id].[chunkhash].js'
},
This makes it so that the filenames are different and it doesn't clash.
EDIT:
One thing i've recently found is that you should use a hash instead of chunkhash if using HMR reloading. I haven't dug into the root of the problem but I just know that using chunkhash was breaking my webpack config
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js',
sourceMapFilename: '[name].[hash:8].map',
chunkFilename: '[id].[hash:8].js'
};
Should work fine with HMR then :)
EDIT July 2018:
A little more information on this.
Hash
This is a hash generated every time that webpack compiles, in dev mode this is good for cache busting during development but shouldn't be used for long term caching of your files. This will overwrite the Hash on every build of your project.
Chunkhash
If you use this in conjunction with a runtime chunk then you can use it for long term caching, the runtime chunk will see what's changed in your source code and update the corresponding chunks hash's. It won't update others allowing for your files to be cached.
I had exactly the same problem. The problem seems to occur with the file-loader. The error went away when I removed the html test and included html-webpack-plugin instead to generate an index.html file. This is my webpack.config.js file:
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
})
module.exports = {
entry: {
javascript: './app/index.js',
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: [
path.resolve(__dirname, '/node_modules/')
],
loader: 'babel-loader'
},
]
},
resolve: {
extensions: ['.js', '.jsx', '.json']
},
plugins: [HTMLWebpackPluginConfig]
}
The html-webpack-plugin generates an index.html file and automatically injects the bundled js file into it.
I had the same issue after upgrading to Webpack 5. My problem was caused by the copy-webpack-plugin.
Below is the original pattern ignoring a specified file, it works with Webpack 4, but throws an error with Webpack 5.
ERROR in Conflict: Multiple assets emit different content to the same
filename default.hbs
plugins: [
new CopyPlugin({
patterns: [
{
from: "./src/academy/templates",
globOptions: {
ignore: ["default.hbs"]
}
},
]
}),
],
To fix the error:
plugins: [
new CopyPlugin({
patterns: [
{
from: "./src/academy/templates",
globOptions: {
ignore: ["**/default.hbs"]
}
},
]
}),
],
By not ignoring the specified file, the default.hbs (a.k.a index.html) was copied twice into the build (a.k.a /disk) directory effectively resulting in Webpack trying to insert multiple assets into the "same" (duplicated) filename.
I had the same problem, and I found these in the documents.
If your configuration creates more than a single “chunk” (as with multiple entry points or when using plugins like CommonsChunkPlugin), you should use substitutions to ensure that each file has a unique name.
[name] is replaced by the name of the chunk.
[hash] is replaced by the hash of the compilation.
[chunkhash] is replaced by the hash of the chunk.
output: {
path:__dirname+'/dist/js',
//replace filename:'app.js'
filename:'[name].js'
}
In my case the source map plugin was conflicting with the extract mini plugin.
Could not find a solution to this anywhere. source maps for css and javascript were writing to the same file. Here is how I finally solved it in my project:
new webpack.SourceMapDevToolPlugin({
filename: '[name].[ext].map'
}),
I encountered this error in my local dev environment. For me, the solution to this error was to force the files to rebuild. To do this, I made a minor change to one of my CSS files.
I reloaded my browser and the error went away.
If you getting same kind error in Angular
Solution : delete cache folder inside .angular folder and
start portal again ng serve
I had the same problem after updating all the dependencies to latest (e.g. webpack 4 -> 5) for a Chrome extension I made about 2 years ago, and managed to solve it.
There were two files in the complaint (popup.html and options.html). Here is my original webpack.config.js file:
const path = require('path');
const CopyPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
target: 'web',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
entry: {
popup: './src/scripts/popup.tsx',
options: './src/scripts/options.tsx',
},
context: path.join(__dirname),
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json', '.css'],
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin([
{ from: 'src/popup.html', to: 'popup.html' },
{ from: 'src/options.html', to: 'options.html' },
{ from: 'src/manifest.json', to: 'manifest.json' },
{ from: 'src/icons', to: 'icons' },
]),
new HtmlWebpackPlugin({
template: path.join("src", "popup.html"),
filename: "popup.html",
chunks: ["popup"]
}),
new HtmlWebpackPlugin({
template: path.join("src", "options.html"),
filename: "options.html",
chunks: ["options"]
}),
]
};
I solved it by removing:
{ from: 'src/popup.html', to: 'popup.html' },
{ from: 'src/options.html', to: 'options.html' },
under new CopyPlugin... part.
So seems like right now there is no need to explicitly copy popup.html and options.html to output folder when HtmlWebpackPlugin is already emitting them.
Similar solution to the above with file-loader, however, I think this solution is the more elegant. Before, I was only specifying the [name], adding the [path][name] resolved my conflict as below:
module: {
rules: [
{
test: /\.(mp4|m4s)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
},
},
],
},
],
I changed index.html file from /public directory to /src to fix this issue. (Webpack 5.1.3)
The same error in a Vue.js project when doing e2e with Karma. The page was served using a static template index.html with /dist/build.js. And got this error running Karma.
The command to issue Karma using package.json was:
"test": "cross-env BABEL_ENV=test CHROME_BIN=$(which chromium-browser) karma start --single-run"
The output configuration in webpack.config.js was:
module.exports = {
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
...
}
My solution: inspired by the Evan Burbidge's answer I appended the following at the end of webpack.config.js:
if (process.env.BABEL_ENV === 'test') {
module.exports.output.filename = '[name].[hash:8].js'
}
And then it eventually worked for both page serving and e2e.
I had a similar problem while upgrading webpack 3 to webpack 4. After upgrading the modules I came across this error.
WARNING in Conflict: Multiple assets emit different content to the same filename alert-icon.svg
WARNING in Conflict: Multiple assets emit different content to the same filename comment.svg
The problem was caused by fileloader for svg. Solved the error by adding a hash name: '[name].[hash:8].[ext]' making it unique every time webpack compiles.
Provinding the code below:
module: {
rules: [
{
test: /\.svg$/,
loader: 'file-loader',
query: {
name: '[name].[hash:8].[ext]'
}
]
}
webpack 5 solution
Add chunkFilename and assetModuleFilename in output as showed below.
output: {
path: path.join(__dirname, "/build/"),
filename: "js/[name].[contenthash].js",
chunkFilename: 'chunks/[name].[chunkhash].js',
assetModuleFilename: 'media/[name][hash][ext][query]'
},

Webpack and Angular HTML image loading

I have been breaking my head with webpack and angular. This might have a simple answer but I cant figure it out. I have read almost every answer here in stack overflow on this topic to no avail.
I have an html page like this (also other template that have images):
<body>
<img ng-src="../images/angular-webpack.png">
<md-button class="md-primary md-raised">
Button
</md-button>
</body>
I also have a webpack config:
var webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var path = require('path');
module.exports = {
context: path.resolve(__dirname + '/src'),
entry: ['./js/core/app.module.js'],
output: {
path: './release',
publicPath:'/',
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.html/,
exclude: 'node_modules',
loader: 'raw-loader'
},
{
test: /\.css/,
exclude: 'node_modules',
loader: 'style-loader!css-loader'
},
{
test: /\.(jpe?g|png)$/i,
exclude: 'node_modules',
loader: 'url-loader?limit=8192!img'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
new CopyWebpackPlugin([
{from: './index.html', to: './index.html'}
], {
ignore: [
'*.txt',
{glob: '**/*', dot: true}
]
})
],
devServer: {
contentBase: './release'
},
watch: true
};
...but i do not see my images loading. I have tried url-loader, file-loader with publicPath and without it. I am confused, I do not know how to format the webpack config or the html image tag for it to work.
Anyone has any experience on getting images to work with webpack? Also I do not want to include my images in the controllers or any other js file. I want the images to be declared in the html page.
The raw-loader is supposed to turn a text file into a CommonJS module that exports the file contents as a string – nothing more.
If you want webpack to recognize the file as HTML and all its references in it, you need the html-loader. The html-loader parses the given file with an HTML parser and picks up references to other files within attributes. By default, that is only <img src="...">. In your case, you need to tell the html-loader to also look for ng-src attributes, like this:
// webpack.config.js
...
loaders: [{
test: /\.html$/,
loaders: [
"html?" + JSON.stringify({
attrs: ["img:src", "img:ng-src"]
})
]}
]

Categories