Webpack file-loader not exporting images - javascript

I am using webpack for my PHP and React project. I want to load a background image from my .scss file with the webpack file-loader but for some reason I don't know, the img-folder does not get copied/exported to my dist-folder. Below is the webpack.config.js:
var webpack = require("webpack");
var path = require("path");
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var WatchLiveReloadPlugin = require('webpack-watch-livereload-plugin');
var DIST_DIR = path.resolve(__dirname, "dist");
var SRC_DIR = path.resolve(__dirname, "src");
var extractPlugin = new ExtractTextPlugin({
filename: 'main.css'
});
module.exports = {
entry: ['babel-polyfill', SRC_DIR + "/app/index.js"],
output: {
path: DIST_DIR + "/app",
filename: "bundle.js",
publicPath: "/dist"
},
watch: true,
module: {
rules: [
{
test: /\.js$/,
include: SRC_DIR,
loader: "babel-loader",
exclude: /node_modules/,
query: {
presets: ["react", "es2015", "stage-2"], plugins: ["transform-decorators-legacy", "transform-class-properties"]
}
},
{
test: /\.scss$/,
use: extractPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "sass-loader", "resolve-url-loader"]
})
},
{
test: /\.css$/,
use: ["css-loader", "sass-loader", "resolve-url-loader"]
},
{
test: /\.(jpg|png)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'img/',
publicPath: 'img/'
}
}
]
}
]
},
plugins: [
extractPlugin,
new WatchLiveReloadPlugin({
port: 'localhost',
files: [
'./dist/app/*.css',
'./dist/**/*.js',
'./src/app/**/*.png',
'./src/app/**/*.jpg',
'./src/app/**/.*.scss',
'./src/**/*.php',
'./src//*.js'
]
})
]
};
I also tried loader: 'file-loader?name=/dist/img/[name].[ext]', but with no luck.
My file structure is like this:
-- dist
-- app
bundle.js
main.css
-- src
-- app
-- css
main.scss
-- img
someimage.jpg
Then in my .scss i tried this:
background-image: url('/img/someimage.jpg');
Does anyone have an idea what's wrong here?

Try to import the image file in one of your script files like
import '/path/to/img.jpg';
this will let Webpack know about the dependency and copy it.

The CSS/Sass loaders do not translate URLs that start with a /, therefore your file-loader won't be applied here.
The solution is to use relative paths for the imports if you want them to be processed by webpack. Note that CSS and Sass have no special syntax for relative imports, so the following are equivalent:
url('img/someimage.jpg')
url('./img/someimage.jpg')
If you want them to be resolved just like a module, webpack offers the possibility to start the import path with a ~, as shown in sass-loader - imports.

Related

Source mapping with webpack for express server

I have an express server that is written in es5 and es6 combined. It consists of js and ts files. So now when I make a webpack build and start the server, it runs fine. But if my code throws an error then the error tracing is not correct i.e source of error (file, line and column number) is not showing correctly.
Is there a way to map the bundle with the source?
I have tried adding:
devTool: "source-map" to webpack config but it doesn't work, it seems to be working with the browser. Is there any way to achieve the same for server-side as well?
Here is my webpack.config.js
const nodeExternals = require("webpack-node-externals");
const webpack = require("webpack");
const path = require("path");
module.exports = {
stats: "detailed",
target: "node",
externals: [nodeExternals()],
entry: {
app: "./server.js",
backupCronApp: "./backup/cron/index.js"
},
output: {
path: path.join(__dirname, "/build"),
filename: "[name].js",
libraryTarget: "commonjs2",
},
plugins: [new webpack.EnvironmentPlugin(["NODE_ENV"])],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.ts', '.js'],
},
};

Set correct path to lazy-load component using Webpack - ES6

In my app.js file I have the following event inside a function where I import another module (same as in the docs) using the lazy-loading technique:
button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
var print = module.default;
print();
});
And in my webpack config I set up this (besides Babel, SASS loaders, etc):
const path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
watch: true,
entry: {
main: ['babel-polyfill', './src/js/app.js','./src/sass/main.sass']
},
output: {
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, "dist"),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ["babel-preset-env", "babel-preset-stage-0"]
}
}
},
{
test: /\.sass$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'sass-loader',
query: {
sourceMap: false,
},
},
],
}),
},
]
}
}
The problem is the path "./print" is from my "src" folder and not from my "dist" folder, where webpack puts all the bundles, so I get a 404 error. If I change the path to "./dist/print" then the webpack build will crash.
Am I missing a webpack configuration?
Edit:
Folder structure:
src
js
app.js
print.js
dist
main.bundle.js
print.bundle.js
You don't have to treat with the modules path in dist folder, only in src folder.
There is two solutions I think :
1/ Specify src path in your import statement :
button.onclick = e => import(/* webpackChunkName: "print" */ './src/js/print').then(module => {
var print = module.default;
print();
});
2/ Personally, What I usually do is to add src folder to resolved paths in config file:
resolve: {
modules: [
path.resolve('./node_modules'),
path.resolve('./src/js')
],
extensions: ['.json', '.js']
},
Your code should then work without changing a line.

How to render CSS using webpack

I'm new to all this, so I apologise in advance if my question seems stupid. I'm having trouble including my CSS file using webpack. My webpack.config.js file looks like this
const HTMLWebpackPlugin = require('html-webpack-plugin');
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
});
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: __dirname + '/app/index.js',
resolve: {
modules: [__dirname, 'node_modules']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
}
]
},
output: {
filename: 'transformed.js',
path: __dirname + '/build'
},
plugins: [
HTMLWebpackPluginConfig,
new ExtractTextPlugin('styles.css')
]
};
When webpack does its thing, my CSS file is not included. I've gone through five or six different tutorials dealing with html-webpack-plugin and different loaders but I can't get it to work.
Try using both css-loader and style-loader together, instead of falling back to one. Like so:
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
CSS loader makes sure to load any necessary imports and files, while style-loader should actually inject the CSS into the webpage.
Taken from the style-loader docs: https://github.com/webpack-contrib/css-loader#usage
Are you requiring/importing the CSS file into your entry point file (or any of the files imported by the entry point)?
As in import './file.css';

Independent chunk files with webpack

I am building a component library and I am using Webpack to bundle it. Some components only rely on html templates, css and JavaScript that I've written, but some components require external libraries.
What I'd like to achieve is a vendor.js that is optional to include if the component you want to use needs it.
For instance, If a user only needs a component without vendor dependencies, it would suffice that they use main.bundle.js which only contains my own code.
In my index.js, I have the following imports:
import { Header } from './components/header/header.component';
import { Logotype } from './components/logotype/logotype.component';
import { Card } from './components/card/card.component';
import { NavigationCard } from './components/navigation-card/navigation-card.component';
import { AbstractComponent } from './components/base/component.abstract';
import { Configuration } from './system.config';
import 'bootstrap-table';
import './scss/base.scss';
All of these imports are my own, expect for bootstrap-table.
I have configured Webpack like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor', // Specify the common bundle's name.
minChunks: function (module) {
// Here I would like to tell Webpack to give
// each bundle the ability to run independently
return module.context && module.context.indexOf('node_modules') >= 0;
}
}),
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, 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" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
This results in two .js files and one .css. However, webpacks common module loading functionality resides in vendor.js, and that renders my main unusable if I don't include vendor first, and it isn't always needed.
To sum it up, if a user only needs the footer (no external dependencies), this would suffice:
<script src="main.bundle.js"></script>
If the user wants to use the table, which has an external dependency, they would need to include both:
<script src="vendor.js"></script>
<script src="main.bundle.js"></script>
Right now, including only main.bundle.js gives me this error:
Uncaught ReferenceError: webpackJsonp is not defined.
I am aware that I can extract all common functionality by adding this after my vendor chunk is created in the Webpack config:
new webpack.optimize.CommonsChunkPlugin({
name: 'common'
})
But this approach still requires the user to include two .js files.
How can I go about achieving this? It seems that it only differs 2 kb when I don't extract the common modules like I do above, and that is fine with me.
Turns out this is very easy to do if you can stand some manual work and actually understand what Webpack does (which I didn't). I solved it like this:
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractScss = new ExtractTextPlugin({
filename: "[name].bundle.css"
});
module.exports = {
entry: {
main: './src/index.ts',
vendor: './src/vendor/vendor.ts'
},
output: {
path: path.resolve(__dirname, 'dist/release'),
filename: "[name].bundle.js",
chunkFilename: "[name].bundle.js"
},
plugins: [
extractScss
],
devtool: "source-map",
resolve: {
// Add `.ts` as a resolvable extension.
extensions: ['.webpack.js', '.web.js', '.ts', '.js', '.ejs']
},
module: {
rules: [
// All files with a '.ts' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.ts?$/, exclude: /node_modules/, 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" },
// Allows for templates in separate ejs files
{test: /\.ejs$/, loader: 'ejs-compiled-loader'},
{
test: /\.scss$/,
use: extractScss.extract({
use: [{
loader: 'css-loader', options: {
sourceMap: true
}
}, {
loader: 'sass-loader', options: {
soureMap: true
}
}]
})}
]
}
}
In vendor.ts, I then simply import any vendor dependencies I have:
import 'jquery';
import 'bootstrap-table';
This results in two different files, both have Webpacks bootstrapping logic.
Hope this helps someone.

How to add header comments to webpack uglified JavaScript?

I am currently using the following webpack.config.js:
var webpack = require('webpack');
module.exports = {
entry: __dirname + "/src/index.js",
output: {
path: __dirname,
filename: "index.js"
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: '/node_modules/',
query: {
presets: ['latest']
}
}
]
},
plugins: [ new webpack.optimize.UglifyJsPlugin({minimize: true}) ]
}
This works exactly how I want it to. But now I want to add some comments with project info to the output file, on top of the one line with uglified code. How do I do this?
Add the comments to the code after minification using Webpack's BannerPlugin():
const webpack = require('webpack');
new webpack.BannerPlugin(banner);
// or
new webpack.BannerPlugin(options);

Categories

Resources