How to render CSS using webpack - javascript

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';

Related

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.

Webpack file-loader not exporting images

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.

How to preload third-party's css and js files using webpack in ReactJS project?

Like using ProvidePlugin to preload jQuery, is there a way to preload a third-party's css and js files instead of using import in the entry js file?
Why I would like to preload these files is that I am getting an error when importing jQuery-ui in the entry js file. Also, I think it is good to preload the libraries.
./assets/js/jquery-ui.min.js
Critical dependencies:
719:76-84 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
# ./assets/js/jquery-ui.min.js 719:76-84
Thank you in advanced!
You should import third party css files at entry on webpack config. like example below:
module.exports = {
entry: {
'main': [
'bootstrap-sass!./src/theme/bootstrap.config.js',
'./src/client.js',
'./src/someCSSFILE.js'
]
},
output: {
path: assetsPath,
filename: 'bundle.js',
publicPath: 'http://' + host + ':' + port + '/dist/',
},
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loaders: ['babel?' + JSON.stringify(babelLoaderQuery), 'eslint-loader']},
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.less$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!less?outputStyle=expanded&sourceMap' },
{ test: /\.scss$/, loader: 'style!css?modules&importLoaders=2&sourceMap&localIdentName=[local]___[hash:base64:5]!autoprefixer?browsers=last 2 version!sass?outputStyle=expanded&sourceMap' },
{ test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: "url?limit=10000&mimetype=application/font-woff" }
]
}

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);

webpack-dev-server watches and compiles files correctly, but browser can't access them

EDIT: Link to github repo where this example is hosted is here in case someone wants to run it
I'm getting the near exact same problem as another user (you can find the question here), in that running the webpack-dev-server does actually compile and watch files correctly (seeing the console output in the terminal), but the browser still can't view my site correctly. This is my webpack.config.js file:
var webpack = require('webpack'),
path = require('path'),
// webpack plugins
CopyWebpackPlugin = require('copy-webpack-plugin');
var config = {
context: path.join(__dirname,'app'),
entry: './index.js',
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js',
publicPath: path.join(__dirname, 'public')
},
devServer: {
// contentBase: './public/'
},
plugins: [
// copies html to public directory
new CopyWebpackPlugin([
{ from: path.join(__dirname, 'app', 'index.html'),
to: path.join(__dirname, 'public')}
]),
// required bugfix for current webpack version
new webpack.OldWatchingPlugin()
],
module: {
loaders: [
// uses babel-loader which allows usage of ECMAScript 6 (requires installing babel-preset-es2015)
{test: /\.js$/, loader: 'babel', exclude: /node_modules/, query: { presets: ['es2015']}},
// uses the css-loader (loads css content) and style-loader (inserts css from css-loader into html)
{test: /\.css$/, loader: 'style!css', exclude: /node_modules/}
]
}
};
module.exports = config;
And this is my directory structure:
+--- webpack/
+--- app/
+--- index.html
+--- index.js
+--- styles.css
+--- package.json
+--- webpack.config.js
Currently, running webpack-dev-server outputs the following in the browser (note the lack of the public/ directory which is where webpack normally outputs my html and javascript bundle):
EDIT: Adding the devServer.contentBase property and setting it to public gets the browser to return a 403 error not found as shown here:
Okay, so I was able to reproduce the issue that you have on my project. To fix the issue I changed some things.
Here is what I have set up. I'm defining a bit less in the output and using jsx instead of js, but the results should be the same. You can replace my src with wherever your source code is.
const config = {
entry: './src/App.jsx',
output: {
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react', 'stage-0'],
plugins: ['add-module-exports']
}
},
{
include: /\.json$/, loaders: ['json-loader']
},
{
test: /\.scss$/,
loaders: ['style', 'css?modules', 'sass']
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file?name=fonts/[name].[ext]'
}
]
},
plugins: [
new webpack.ProvidePlugin({
'Promise': 'exports?module.exports.Promise!es6-promise',
'fetch': 'imports?self=>global!exports?global.fetch!isomorphic-fetch'
}),
new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
],
resolve: {
root: path.resolve('./src')
},
devServer: {
contentBase: 'src'
}
};
So basically you would want this output in terminal:
webpack result is served from / - tells us that whatever we build from will be at the root
content is served from src - tells us that it's building from that directory
Hope this helps

Categories

Resources