I've used Grunt and Gulp before so webpack is a bit new to me still.
Now I've configured webpack to successfully bundle my javascript perfectly. The issue I'm having now is bundling my sass and outputting the result to a file.
My understanding is that I have to use extract-text-webpack-plugin to extract the styles to its own file rather in inlining in <head>, but I'm not sure on this part. I'm looking to do the following for sass:
Compile the contents of src/main/stylesheets/**/*.scss
Output the contents to a single file app/assets/stylesheets/bundle.css
I know I can achieve this using gulp/grunt easily, but I'm trying to learn how webpack does things. My webpack.config.babel.js is as follows:
import path from "path";
import ExtractTextPlugin from "extract-text-webpack-plugin";
export default {
entry: {
index: path.join(__dirname, "src/main/javascripts/application.js")
},
output: {
path: path.join(__dirname, "app/assets/javascripts/"),
publicPath: "/assets/",
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.scss$/,
include: path.join(__dirname, "src/main/stylesheets/"),
loader: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader",
query: { modules: false, sourceMaps: true }
},
{
loader: "sass-loader",
query: { sourceMaps: true }
}
]
})
},
{
test: /\.js$/,
include: path.join(__dirname, "src/main/javascripts/"),
exclude: /node_modules/,
use: [
{ loader: "babel-loader" }
],
}
]
},
plugins: [
new ExtractTextPlugin(path.join(__dirname, "app/assets/stylesheets/bundle.css"))
]
}
Dependencies from package.json if that matters:
"dependencies": {
"bootstrap-sass": "^3.3.7",
"jquery": "^3.1.1"
},
"devDependencies": {
"babel-core": "^6.23.1",
"babel-loader": "^6.3.1",
"babel-preset-env": "^1.1.8",
"css-loader": "^0.26.1",
"extract-text-webpack-plugin": "^2.0.0-rc.3",
"node-sass": "^4.5.0",
"sass-loader": "^6.0.0",
"style-loader": "^0.13.1"
}
Posting here because there isn't really room in the comments...if you have a link to the repo I might be able to be more helpful. Your syntax doesn't look wrong necessarily, but I am posting this because it's the most recent example I have that I know works: you might want to try using option instead of query. It doesn't look like query is deprecated based on the documentation, but this setup worked for me (although I wasn't using extract here),
{
test: /\.scss$/,
use: [
'style-loader?sourceMap',
{
loader: 'css-loader',
options: {
sourceMap: true,
importLoaders: 2,
}
},
'postcss-loader?sourceMap',
'sass-loader?sourceMap'
],
exclude: [path.resolve('node_modules')],
},
Related
How should I import npm packages? If I just add lodash bundling goes from 6ms to 900ms!?
Is there no way to cache static dependencies?
If I add lodash to external, globals and customResolveOptions in rollup.config.js it is excluded from the bundle. But how could I add it in a libs.js file for example?
Here are my files:
app.js
import _ from 'lodash'
alert(_.concat(["hi", "hello"]))
rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify';
import babel from 'rollup-plugin-babel';
const production = !process.env.ROLLUP_WATCH;
export default {
input: 'src/index.js',
output: {
file: 'scripts/bundle.js',
format: 'iife',
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
babel({
exclude: 'node_modules/**'
}),
production && uglify()
]
};
package.json
{
"devDependencies": {
"npm-run-all": "^4.1.2",
"rollup": "^0.55.5",
"rollup-plugin-commonjs": "^8.0.2",
"rollup-plugin-node-resolve": "^3.0.0",
"rollup-plugin-uglify": "^3.0.0",
"babel-core": "^6.26.3",
"babel-plugin-external-helpers": "^6.22.0",
"babel-preset-env": "^1.7.0",
"rollup-plugin-babel": "^3.0.4"
},
"dependencies": {
"lodash": "^4.17.10"
},
"scripts": {
"build": "rollup -c",
"watch": "rollup -c -w",
"dev": "npm-run-all --parallel watch"
},
...
}
You can manually separate the entrypoints for "libs" and source code to speed up your build:
rollup.config.js
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify';
import babel from 'rollup-plugin-babel';
const production = !process.env.ROLLUP_WATCH;
export default [{
input: 'src/index.js',
output: {
file: 'scripts/bundle.js',
format: 'iife',
sourcemap: true,
globals: {
'lodash': '_',
},
},
external: ['lodash'],
plugins: [
babel(),
production && uglify()
]
}, {
input: 'src/common.js',
output: {
file: 'scripts/common.js',
format: 'umd',
name: 'window',
extend: true,
sourcemap: true
},
plugins: [
resolve(),
commonjs(),
production && uglify()
]
}];
common.js
export { default as _ } from 'lodash'
It does add the overhead of maintaining the common.js file with libraries. Personally, I find it gives the best control over file size and compile time. If you're constantly installing and including new npm packages, this will be be hard to maintain.
I'm trying to add autoprefixer to webpack 2.2.1 and having issues seeing the prefixes.
I installed postcss-loader https://github.com/postcss/postcss-loader as this seems to be the listed way to handle postcss in webpack.
I'm currently using scss files which I'm importing into my react files.
example: import styles from '../../styles/header.scss';
This is handled in webpack using sass-loader.
I'm not getting any error with my setup but I'm also not seeing any autopre-fixing going on to my files ? I presume this only needs to be added in development not production ?
Here is my dev setup webpack config.
const path = require('path')
const webpack = require('webpack')
const ROOT_DIR = path.resolve(__dirname, '../app')
module.exports = {
devtool: 'eval',
entry: [
`${ROOT_DIR}/js/index`,
'webpack-hot-middleware/client'
],
output: {
path: path.resolve(__dirname, '../public'),
filename: 'bundle.js',
publicPath: '/public/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
"config.ASSET_URL": JSON.stringify(process.env.ASSETS_URL),
"config.GA_TRACKING_ID": JSON.stringify(process.env.GA_TRACKING_ID)
})
],
module: {
loaders: [
{ test: /\.js?$/,
loader: 'babel-loader',
include: path.join(__dirname, '../app'),
exclude: /node_modules/
},
{ test: /\.scss?$/,
include: path.join(__dirname, '../app', 'styles'),
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: { plugins: [
require('autoprefixer')
] }
},
{
loader: 'sass-loader',
options: {
data: "$assetPath: '" + process.env.ASSETS_URL + "';"
}
}
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
include : path.join(__dirname, '../app', 'images'),
loader : 'file-loader?limit=30000&name=[name].[ext]'
},
{
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
include : path.join(__dirname, '../app', 'fonts'),
loader: 'file-loader?name=fonts/[name].[ext]'
}
]
}
}
I had a to deal with sometime similar recently. Check if it works if you create a separate postcss.config.js file in the directory of your scss files with this in it
//postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
and in your webpack config
{ test: /\.scss?$/,
include: path.join(__dirname, '../app', 'styles'),
use: [
{loader: "style-loader"},
{loader: "css-loader"},
{loader: "postcss-loader"},
{loader: "sass-loader",
options: {
data: "$assetPath: '" + process.env.ASSETS_URL + "';"
}
}
]
},
I try to run our ASP.NET MVC project with webpack2. As the first step, I set up webpack2 with ExtractTextPlugin.
When running webpack watch, I can see that the bundled css file gets updated.
But if I run the project with IISExpress and with webpack watch running, the browser just won't pickup the latest change even though the file has changed.
Verified that if I turn off webpack watch and refresh the browser, then I can see those changes in the browser.
I am running without webpack dev server, here is the webpack.config.js:
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const path = require('path');
module.exports = env => {
return {
entry: {
"main": "./static/entry.js",
"component": path.resolve(__dirname, "../component/static/bundle.js")
},
output: {
path: path.resolve(__dirname, "./static/dist/scripts"),
filename: "[name].index.js"
},
module: {
rules: [
{
test: /\.scss$/,
exclude: /node_modules/,
use:ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: 'css-loader',
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
includePaths: [
path.resolve(__dirname, './default.css'),
path.resolve(__dirname, './normalize.css')
]
}
}
]
})
},
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.ts$/, loader: 'babel-loader', exclude: /node_modules/ }
]
},
plugins: [
new webpack.ProvidePlugin({
$: path.resolve(__dirname, './node_modules/jquery/src/jquery'),
jQuery: path.resolve(__dirname, './node_modules/jquery/src/jquery'),
moment: path.resolve(__dirname, './node_modules/moment/moment')
}),
new ExtractTextPlugin({
filename: "../style/[name].style.css",
allChunks: true
}),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compress: {
warnings: false
}
})
]
}
};
The issue is constant and I have no idea what could have happened, help please.
I found the cause of this problem.
Project web.config is caching the client resources, disable output caching fixed the issue.
<caching>
<outputCache enableOutputCache="false" />
</caching>
Im trying to figure out why a css segment will not run through 'style-ext-html-webpack-plugin'.
Currently I have a .CSS file with rules for the splash screen.
It's being extracted using 'extract-text-webpack-plugin' and injected to the template's <head> with 'extract-text-webpack-plugin'.
problem is, the file never gets run through 'style-ext-html-webpack-plugin' and I can't wrap my head around how to debug it.
(Ideally, I'd like to have a .SCSS file so it can be themeable through a .env file. i.e: have splash.scss exclusively extracted and inlined in the <head> after being injected with some theme colors)
webpack.config.js:
....
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlPlugin = require('style-ext-html-webpack-plugin');
const extractSplashCSS = new ExtractTextPlugin('splash.css');
module.exports = {
entry: {...},
output: {...},
resolve: {...},
plugins: [
...,
new HtmlWebpackPlugin({
title: enviroments.TITLE,
splashScreenTitle: enviroments.SPLASH_SCREEN_TITLE,
template: 'src/index.html',
cache: true,
favicon: enviroments.FAVICON || './src/assets/images/favicon.ico',
inject: 'body'
}),
extractSplashCSS,
new StyleExtHtmlPlugin('splash.css')
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{
test: /\.css$/,
loader: 'style-loader!css-loader!resolve-url-loader?import=false',
exclude: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.css$/,
loader: extractSplashCSS.extract({
use: 'css-loader'
}),
include: [path.join(path.resolve('./src'), 'common/app/splash.css')]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader?importLoaders=1',
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
'resolve-url-loader?sourceMap',
{
loader: 'sass-loader?sourceMap',
options: {
includePaths: path.resolve('./src'),
data: `
$color-primary: ${theme.PRIMARY};
....
`
}
}
]
},
....
]
}
};
index.js:
...
// above the fold css
import 'common/app/splash.css';
Needed to update html-webpack-plugin to 2.29.0.
I've managed to solve this issue, using a sass file that can be themeable with variables from .env file:
I had to explicitly exclude the splash file from the normal sass flow and create another loader definition explicitly for it:
...
const ExtractTextPlugin = require('extract-text-webpack-plugin'); //used for above-the-fold css (such as splash-screen)
const StyleExtHtmlWebpackPlugin = require('style-ext-html-webpack-plugin');
module.exports = {
...
plugins: [
...
new HtmlWebpackPlugin({
...
}),
new ExtractTextPlugin('splash.css'),
new StyleExtHtmlWebpackPlugin('splash.css'),
],
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.css$/, loader: 'style-loader!css-loader!resolve-url-loader?import=false' },
{
test: /\.scss$/,
exclude: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: [
.....
]
},
{
test: /\.scss$/,
include: [path.join(path.resolve('./src'), 'common/app/splash.scss')],
use: ExtractTextPlugin.extract({
use: [
{
loader: 'css-loader',
options: {minimize: true}
},
{
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')];
}
}
},
{
loader: 'sass-loader',
options: { data: `$color-primary: ${theme.PRIMARY};` }
}
]
})
},
]
}
};
I would like you to help/suggest the best way to use datepicker from jquery-ui having the following file structure:
-single_pages
-admin
-admin.js
-webpack.config.js
-common
-DatesFilter
-DatesFilter.js
-node_modules
-package.json
I already installed jquery-ui
My webpack.config.js file is:
var path = require('path');
var webpack = require("webpack");
module.exports = {
resolve: {
alias: {
'jquery': require.resolve('jquery'),
},
root: [
path.resolve(__dirname, './../admin'),
path.resolve(__dirname, './../common')
],
extensions: ['', '.js'],
fallback: path.resolve(__dirname, './../node_modules')
},
resolveLoader: {
fallback: path.resolve(__dirname, './../node_modules')
},
entry: './index.js',
output: {
filename: 'bundle.js',
publicPath: "/"
},
externals: {
// require("jquery") is external and available
// on the global var jQuery
"jquery": "jQuery"
},
plugins: [
new webpack.ProvidePlugin({
"$":"jquery",
"jQuery":"jquery",
"window.jQuery":"jquery"
})
],
module: {
loaders: [
{
test: /\.js$/,
include: [
path.resolve(__dirname, './')
],
loader: "babel-loader"
},
{
test: /\.js$/,
include: path.resolve(__dirname, './../common'),
babelrc: false,
loader: require.resolve('babel-loader'),
query: { // load the same presets as in the .babelrc file, but in a way that resolves in the parent directory
presets: [require.resolve('babel-preset-es2015'), require.resolve('babel-preset-react'),
require.resolve('babel-preset-stage-0')]
}
}
]
}
};
I'm using React.js.
I import DatesFilter.js inside admin.js. I get to see the component. The problem comes when I want to use the datepicker.
DatesFilter.js uses datepicker from jquery-ui
I'm using: import { datepicker } from 'jquery-ui' inside DatesFilter.js but it keeps saying TypeError: $(...).datepicker is not a function
What can I do?
Thank you
Try importing just the module, see this link jquery-ui-and-webpack-how-to-manage-it-into-module
in your case you would import "jquery-ui/ui/widgets/datepicker"