Resolve url() to image without bundling - javascript

I'm integrating Webpack into an already established front-end environment. Sass and resolve-url-loader are working and Webpack finds the files that are referenced by the url() in the CSS. My problem is, I don't want to copy the files referenced by url() into the dist/ folder, I want to link to them where they are.
My files are setup like this
www/
index.html
assets/
js/
main.js
css/
main.scss
components/
thing.scss
images/
pic.jpg
dist/
output.js
output.css
with main.scss importing thing.scss which contains the line
background: url(../../images/pic.jpg)
resolve-url-loader correctly resolves this to be ../images/pic.jpg and css-loader finds the file and the loader for the file (file-loader) is called. However, I would like to not copy the file into dist/ (which I did by adding emitFile: false to file-loader) and to rewrite the url to be relative from the CSS output (../assets/images/pic.jpg). How do I do this?
For reference, here is my webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
{
entry: './assets/js/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'output.js',
publicPath: 'dist/'
},
module: {
rules: [{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader, {
loader: "css-loader",
options: {
sourceMap: true,
url: false
}
}, {
loader: "resolve-url-loader",
options: {
debug: true,
sourceMap: true
}
}, {
loader: "sass-loader",
options: {
sourceMap: true,
sourceMapContents: false
}
}
]
}, {
test: /\.(png|svg|jpg|gif)$/,
use: [{
loader: 'file-loader',
options: {
emitFile: false
}
}]
}]
},
plugins: [new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})],
}

Not the best answer but it works.
Remove resolve-url-loader and keep css-loader on url:false. Then just write your URL paths as they would work from the output file.
I'll probably accept it and bundle my images though.

Related

Webpack can't resolve relative path import express static

I'm working on an outlook addin I have an express server running. I am setting webpack because I need to transpile js to es5 to make it work in Outlook Desktop. Here is the simplified project structure.
/public
/javascripts
ssoAuth.js
/addin
/commmands
commands.js
commands.html
/server
/bin
/helpers
app.js
The public folder is set as a static folder in my express server
app.use(express.static(path.join(__dirname, '../public'),
My problem is in commands.js I import ssoAuth.js with es6 module import with relative path :
import getGraphAccessToken from "/javascripts/ssoAuthES6.js";
It works fine when I run node ./server/app.js and load my outlook addin, but when I want to use Webpack to bundle, the import is not working, I get :
ERROR in ./addin/commands/commands.js
Module not found: Error: Can't resolve '/javascripts/ssoAuth.js'
I can't figure out how to configure webpack to allow the imports from the public folder.
Here are my webpack config files :
webpack.config.js :
const config = {
devtool: "source-map",
entry: {
polyfill: "#babel/polyfill",
commands: "./addin/commands/commands.js"
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"]
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"]
}
}
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader"
},
{
test: /\.(png|jpg|jpeg|gif)$/,
use: "file-loader"
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./addin/commands/commands.html",
chunks: ["polyfill", "commands"]
})
]};
webpack.server.config.js :
return ({
entry: {
server: './server/bin/www',
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
node: {
__dirname: false,
__filename: false,
},
externals: [nodeExternals()],
module: {
rules: [
{
// Transpiles ES6-8 into ES5
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
},
plugins: [
new CopyWebpackPlugin([
{
to: "./public",
from: "./public"
}
])
]})
Can you help figure this out ? Is there a better folder structure that I should use to make it work ?
Thanks
You're using an absolute path
import getGraphAccessToken from "/javascripts/ssoAuthES6.js";
// ^ this will look in your topmost directory on your OS
The relative path, from commands.js, would be:
import getGraphAccessToken from "../../javascripts/ssoAuthES6.js";
Alternatively, you can set Webpack to look for modules from your root directory by adding the following to your webpack configuration:
{
// ...
resolve: {
modules: [path.resolve(__dirname, "src"), "node_modules"],
},
// ...
}
Then you can import from your project's root directory from anywhere, like so:
import getGraphAccessToken from "javascripts/ssoAuthES6.js";
Some other points:
Since you're setting the extensions: [".ts", ".tsx", ".html", ".js"], you don't need to provide file extensions for those imports
You specify .ts and .tsx in your webpack config, but you are using .js files. Consider removing the Typescript extensions
If you are using Typescript, you will need to update import paths in your tsconfig.json
You can consider import path aliases in both Webpack and Typescript to be more explicit that your imports are coming from your project root. Instructions here

how to run a different html file instead of index.html when webpack server runs?

When I run webpack server, Below config by default opens index.html available in public folder.
so, Instead of index.html, I want to create another.html or may be like a folder inside which an html eg. public/someFolder/another.html and want to open it, when webpack server is run.
how to run a different html file instead of index.html when webpack server runs?
webpack.config.js
const path = require("path");
module.exports = {
entry: "./myFile.js",
output: {
path: path.join(__dirname, "public"),
filename: "bundle.js",
},
module: {
rules: [
{
loader: "babel-loader",
test: /\.js$/,
exclude: /node_modules/,
},
{
test: /\.s?css$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
devtool: "cheap-module-eval-source-map",
devServer: {
contentBase: path.join(__dirname, "public"),
historyApiFallback: true,
},
};
Have a look at HtmlWebpackPlugin
You can specify a custom path and a custom .html file.
output: {
filename: './dist/subdirectory/myindex.html'
},
plugins: [new HtmlWebpackPlugin()]
The default is of course index.html

How to simply load images with src attribute with webpack 4?

Im stuck and can't get to work my webpack configuration for loading images with src attribute from HTML. I cloned a repo with full setup of webpack, but I know there is a way to simply customize and load images directly from HTML.
Webpack.config.js file:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].bundle.js"
},
mode: "development",
devServer: {
contentBase: path.join(__dirname, "../build"),
compress: true,
port: 3000,
overlay: true
},
devtool: "cheap-module-eval-source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require() on a file into a url
and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets",
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder before re-build again
new CleanWebpackPlugin(),
// The plugin will generate an HTML5 file for you that includes all your webpack bundles
in
the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
Before this project I was able to make that images would simply load from HTML but now ironicly im stuck and can't get this working.
Any help will be very appriciated.
When loading a image directly form HTML, I get the following error:
Error: Child compilation failed:
Module not found: Error: Can't resolve '
./src/assets/images/portret.jpg' in '/home/viktoras/www/sites/painter-new/src':
You can do this:
<img src="<%=require('./src/assets/logo.png')%>">
Plugin Conf
$new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html'
}),

Webpack4 how to load images and custom javascript directly from HTML file?

I want to load images directly from HTML with Webpack 4 and add custom Javascript files to my HTML file but both files inspected at console show Not found 404.
How to properly load images and Javascipt files with Webpack 4?
My Webpack 4 config file:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].bundle.js"
},
mode: "development",
devServer: {
contentBase: path.join(__dirname, "../build"),
compress: true,
port: 3000,
overlay: true
},
devtool: "cheap-module-eval-source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require() on a file into a url and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets",
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder before re-build again
new CleanWebpackPlugin(),
// The plugin will generate an HTML5 file for you that includes all your webpack bundles in the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
]
My webpack.prod.js file:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-
plugin");
const BrotliPlugin = require("brotli-webpack-plugin");
const PurgecssPlugin = require('purgecss-webpack-plugin');
const glob = require("glob");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].[chunkhash:8].bundle.js",
chunkFilename: "[name].[chunkhash:8].chunk.js"
},
mode: "production",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using
Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with
PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by
default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require()
on a file into a url and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets/"
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
optimization: {
minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
}
},
chunks: "all"
},
runtimeChunk: {
name: "runtime"
}
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder
before re-build again
new CleanWebpackPlugin(),
// PurgecssPlugin will remove unused CSS
new PurgecssPlugin({
paths: glob.sync(path.resolve(__dirname, '../src/**/*'), { nodir:
true })
}),
// This plugin will extract all css to one file
new MiniCssExtractPlugin({
filename: "[name].[chunkhash:8].bundle.css",
chunkFilename: "[name].[chunkhash:8].chunk.css",
}),
// The plugin will generate an HTML5 file for you that includes all
your webpack bundles in the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
My project nesting:
--Build
--src
----html
----js
----styles
----assets
------images
I want that files would load simply:
<img src="assets/images/myimage.jpg">
<srcipt src="js/custom.js"></script>
Any help would be appreciated.
Ironically this is my second project with Webpack 4 and this time I can't fix this issue, the first time there was no problem.
This is how img work in Webpack:
<img src=require("./assets/images/myimage.jpg")>
if you use "require" with file-loader, you need to add default.
<img src=require("./assets/images/myimage.jpg").default>
For script tag, src should be your output bundle.js file; because Webpack writes all the code into the bundle.js with the help of Babel. So when browser request html, browser will have only one Javascript file which is the bundle to download. That is the whole point of bundle, smaller bundle.js is better for performance.
// According to your Webpack config, it is main.bundle.js
<srcipt src="main.bundle.js"></script>
but in order to browser to use this main.bundle.js, it has to be publicly available. So you need express to define the public folder, when browser looks for main.bundle.js, you app will be looking into the public folder and if that file exists, it will ship it to the browser.
const express = require("express");
const server = express();
const staticMiddleware = express.static("build");
server.use(staticMiddleware);

How to bundle JS and CSS file independently with Webpack?

I have a few JS and SCSS files. I need Webpack 4 to bundle each JS entry to one JS file and each SCSS entry to one CSS file. The JS files don't import the SCSS files. I try to do it with the following webpack.config.js:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: {
scriptFoo: './src/js/scriptFoo.js',
scriptBar: './src/js/scriptBar.js',
// ...
styleBaz: './src/css/styleBaz.scss',
styleBaq: './src/css/styleBaq.scss'
// ...
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.(scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css'
})
]
};
It works fine, Webpack puts the compiled files to the dist directory. But it also creates an excess dummy JS file for each SCSS file in the dist directory:
webpack.config.js
src/
js/
scriptFoo.js
scriptBar.js
...
css/
styleBaz.scss
styleBaq.scss
...
dist/
scriptFoo.js
scriptBar.js
...
styleBaz.css
styleBaz.js // Excess
styleBaq.css
styleBaq.js // Excess
...
How to make Webpack not to create the excess JS files?
Use the ignore-emit-webpack-plugin Webpack plugin to not create the excess file. First install it by running in a console:
npm install --save-dev ignore-emit-webpack-plugin
Then add it to your Webpack configuration:
const IgnoreEmitPlugin = require('ignore-emit-webpack-plugin');
module.exports = {
// ...
plugins: [
// ...
new IgnoreEmitPlugin(['styleBaz.js', 'styleBaq.js']) // Or simply: new IgnoreEmitPlugin(/^style.*\.js$/)
]
};
It is because for each property in the entry object ,The js file is created in output destinations.
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
Webpack creating dummy js when css is an entry point is a known bug, which has not been fixed yet.
Also having multiple entry files in the entry configuration will also affect treeshaking capabilties

Categories