Is webpack the tool that I need to pass several less files into one minified CSS file?
if so, I'm not sure what I'm doing wrong in the code below?
Is there a way of outputting to different file paths, right now my js file outputs to './assets/javascripts/bundle/', I would like my css file to output to './assets/stylesheets/bundle/' , how would I do this?
Update
I did a test and I can build my less files to one css file but still can't find out how to set multiple paths for the output folder, now I have to comment out the js entry part and change output path...
webpack config
var path = require('path');
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: {
'MediaIndex':['./assets/javascripts/Media/Index/Base.js'],
// stylesheets
'MediaIndexStyleSheet':['./assets/stylesheets/Media/Index/Base.js']
},
output: {
path: './assets/javascripts/bundle/',
filename: '[name].js'
},
resolve: {
alias: {
jquery: path.join(__dirname, "assets/javascripts/lib/jquery-1.11.1.min.js"),
"jquery-ui": path.join(__dirname, "assets/javascripts/lib/jquery-ui.min.js"),
}
},
plugins: [
new webpack.ProvidePlugin({
jQuery: "jquery",
$: "jquery"
}),
new ExtractTextPlugin("[name].css")
],
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
}
]
},
};
assets/stylesheets/Media/Index/Base.js
require('../../../Global/Config.less');
require('../../../Global/Fp.less');
require('../../../Global/Urb.less');
require('../../../Global/Ad1.less');
require('./Nav0.less');
require('./Index.less');
require('./Content.less');
Config.less
#color: 'red';
Index.less
body {
background-color: #{color};
}
You're almost there. Like you already did, you can get all your styling into one css file using ExtractTextPlugin. To put your js and css into a different directories, you can just define a path in ExtractTextPlugin or output.filename that is relative to your output.path. For example:
output: {
path: './assets',
filename: './javascripts/bundle/[name].js'
},
plugins: [
new ExtractTextPlugin("./stylesheets/bundle/[name].css")
]
Related
I am going through webpack tutorials and it teaches how it is possible to minify and output images that have been imported in main index.js file.
However I would like to minify all image assets, regardless whether they were imported in the index.js or not. Something that was easily done in gulp by having a watch set up on the folder. Does webpack follow same format?
This is my webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules : [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]'
}
},
{
loader: 'image-webpack-loader',
}
]
}
]
}
};
No, webpack does not follow the same "logic" as gulp. Webpack """""watches""""" for changes in files that are linked throughout the entire dependency tree. This means that the file you wan't to touch HAS TO BE imported somewhere.
When running my app on webpack dev server, all my image files are working whether as img tags in my index.html or background-image: url()..
Running my project though in production build, I am getting file reference errors that they cannot be found.
GET file:///img/featured.png net::ERR_FILE_NOT_FOUND
GET file:///img/header-img1-1.jpg net::ERR_FILE_NOT_FOUND
I added the copy webpack plugin as I thought this would move all images from my src/img folder to my img folder inside dist.
Should I be using the contentBase option for webpack-dev-server? Or is the copy-webpack-plugin not getting the correct reference? Super confused
Project tree:
- webpack.config.js
- package.json
- .babelrc
- src
- js
- index.js
- ...
- img
- ALL IMAGES LOCATED HERE
- scss
- layout
- landing.scss
- brands.scss
- base
- index.html
inside landing.scss
i have used
background: url('~/img/img-title.png')
same in other files like brands.scss
background: url('~/img/img-title.png')
Which has all worked fine, and I think I've confused myself with how images are referenced with webpack/sass loader, and can't seem to work out how to get the image paths to work for both dev/production, i can only seem to get one working at a time.
production tree:
- dist
- css
- img
- js
- index.html
webpack.config.js:
const path = require('path');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractPlugin = new ExtractTextPlugin({
filename: 'css/main.css'
});
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ScriptExtPlugin = require('script-ext-html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = (env) => {
const isProduction = env.production === true
return {
entry: './src/js/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
use: 'babel-loader'
},
{
test: /\.css$|\.scss$/,
include: path.resolve(__dirname, 'src'),
use: extractPlugin.extract({
fallback: "style-loader",
use: [
{ loader: 'css-loader', options: { importLoaders: 2, sourceMap: true }},
{ loader: 'postcss-loader', options: { sourceMap: true, plugins: () => [autoprefixer] }},
{ loader: 'sass-loader', options: { sourceMap: true }},
],
})
},
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.(jpe?g|png|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 1000,
name: 'img/[name].[ext]',
}
}
]
}
]
},
plugins: [
extractPlugin,
new HtmlWebpackPlugin({
filename: 'index.html',
inject: true,
template: './src/index.html'
}),
new ScriptExtPlugin({
defaultAttribute: 'async'
}),
new CleanWebpackPlugin(['dist']),
new CopyWebpackPlugin([
{from:'src/img',to:'img'}
]),
]
}
}
I think you're using different folder structure on production than on local, i.e. on local, it's just http://localhost:PORT/app, but on prod, it must be similar to http://produrl/Some_Folder/app
Now coming to actual issue - It's your CSS loader.
By default css-loader, has url=true, causing all URLs to be mapped relative to root. Hence this works for you -
background: url('~/img/img-title.png')
but this doesn't
background: url('../../img/img-title.png')
Just set url=false, and you'll be able to provide relative URL and it'll load for all enviorments correctly.
While the accepted answer may works in your specific scenario, I think there is a better solution that do not involve disabling css-loader url() handling and will works better in most of situation.
Tilde ~ problem
When you use ~ to import something in css, css-loader will search for that file inside node_modules. Your images are inside src/img folder so you do not need tilde ~ to import your images.
url() problem
sass-loader doesn't not resolve url() correctly if they are not in the same directory of the entry-file.
In your specific example you import some urls inside src/scss/layout/landing.scss and src/scss/layout/brands.scss but I guess your main scss entry point is inside src/scss folder.
Note: for "main scss entry point" I mean the scss file that you import inside your javascript entry point src/js/index.js
So, in your example, every images imported within a scss file that is not inside src/scss folder will trow an error.
To solve this problem use resolve-url-loader which resolves relative paths in url() statements based on the original source file.
[
{ loader: 'css-loader'}, // set `importLoaders: 3` if needed but should works fine without it
{ loader: 'postcss-loader'},
{ loader: 'resolve-url-loader' }, // add this
{ loader: 'sass-loader',
// sourceMap is required for 'resolve-url-loader' to work
options: { sourceMap: true }
}
]
CopyWebpackPlugin is optional
Based on your configuration you do not need CopyWebpackPlugin because your images are already handle by url-loader.
Note: url-loader doesn't output your images but inline them, images are outputted by file-loader when the file is greater than the limit (in bytes).
file-loader will output your images in dist/img folder, because you set name: 'img/[name].[ext]', and you set output.path: path.resolve(__dirname, 'dist').
Hey I think your issue is just in how you're referencing the image in your scss.
Based on your folder structure it should be:
background: url('../../img/img-title.png')
You could modify the "publicPath" URL (which is relative to the server root) to match the file structure.
//webpack.config.js
...
module: {
rules: [
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "assets/images/",
publicPath: "/other-dir/assets/images/"
}
}
]
}
]
}
I am trying to extract CSS into its own file when imported into a JavaScript file. The initial build works fine, but when I am watching the files, and I comment out the line that imports the css (import './test.css';), webpack only rebuilds the JS file, and the CSS file (main.css) is not updated (it leaves the styles in the stylesheet).
When I comment out the css import, how can I get the css file to rebuild?
webpack.config.js
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'static'),
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin('main.css')
],
};
index.js
// If I comment out the following import while the watch is running,
// it will not remove the CSS from main.css
import './test.css';
document.body.innerText = 'Hello';
test.css
body {
background: lightcoral;
}
I'm working on a new module for an existing project that still uses requireJS for module loading. I'm trying to use new technologies for my new module like webpack (which allows me to use es6 loaders using es6 imports). It seems like webpack can't reconcile with requireJS syntax. It will say things like: "Module not found: Error: Can't resolve in ".
Problem: Webpack won't bundle files with requireJS/AMD syntax in them.
Question: Is there any way to make webpack play nice with requireJS?
My final output must be in AMD format in order for the project to properly load it. Thanks.
I had the same question and I managed to achieve it. Below is the same webpack.config.js file.
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
let basePath = path.join(__dirname, '/');
let config = {
// Entry, file to be bundled
entry: {
'main': basePath + '/src/main.js',
},
devtool: 'source-map',
output: {
// Output directory
path: basePath + '/dist/',
library: '[name]',
// [hash:6] with add a SHA based on file changes if the env is build
filename: env === EnvEnum.BUILD ? '[name]-[hash:6].min.js' : '[name].min.js',
libraryTarget: 'amd',
umdNamedDefine: true
},
module: {
rules: [{
test: /(\.js)$/,
exclude: /(node_modules|bower_components)/,
use: {
// babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
loader: 'babel-loader',
options: {
presets: ['es2015'],
plugins: []
}
}
}, { test: /jQuery/, loader: 'expose-loader?$' },
{ test: /application/, loader: 'expose-loader?application' },
{ test: /base64/, loader: 'exports-loader?Base64' }
]
},
resolve: {
alias: {
'jQuery': 'bower_components/jquery/dist/jquery.min',
'application': 'main',
'base64': 'vendor/base64'
},
modules: [
// Files path which will be referenced while bundling
'src/**/*.js',
'src/bower_components',
path.resolve('./src')
],
extensions: ['.js'] // File types
},
plugins: [
]
};
module.exports = config;
what I'd like to achieve is the simplest way to concat and minify CSS with Webpack. I (successfully) tried ExtractTextPlugin and OptimizeCssAssetsPlugin, as follows
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
entry: {
app: "./assets/js/main.js"
},
output: {
path: 'dist',
filename: "main.bundle.js"
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: "style.min.css",
allChunks: true
}),
new OptimizeCssAssetsPlugin()
]
}
But this only works requiring CSS files from within JS file, like that
require("../../css/normalize.css");
require("../../css/modal.css");
I would like JS files had nothing to do with CSS files.
My question is: how can I avoid requiring CSS file from JS entry point, and thus how can I specify in webpack.config.js what CSS file to concat and minify? So I want to write in webpack.config.js something like "i want to concat and minify all CSS files contained in /assets/css/ folder".
Thank you