Hi Nenad
Thank you for your amazing work. Super cool. Your webpack config is super clean and relatively easy to understand for me.
I have taken your work and changed it a bit:
my package.json looks like this:
{
"name": "webpack-config",
"version": "1.1.0",
"description": "This is my Webpack 4 configuration for static projects.",
"scripts": {
"watch": "webpack-dashboard -- webpack --progress --hide-modules --mode development",
"dev": "webpack-dev-server --progress --hide-modules --mode development",
"build": "webpack --progress --hide-modules --mode production"
},
"author": {
"name": "Nenad Novaković",
"email": "[email protected]",
"url": "https://github.com/dvlden"
},
"license": "MIT",
"browserslist": [
"last 1 major version",
"> 1%"
],
"devDependencies": {
"@babel/core": "^7.0.0-rc.1",
"@babel/preset-env": "^7.0.0-rc.1",
"autoprefixer": "^9.1.2",
"babel-loader": "^8.0.0-beta.4",
"browser-sync": "^2.24.6",
"browser-sync-webpack-plugin": "^2.2.2",
"clean-webpack-plugin": "^0.1.19",
"copy-webpack-plugin": "^4.5.2",
"css-loader": "^1.0.0",
"cssnano": "^4.0.5",
"file-loader": "^1.1.11",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"image-webpack-loader": "^4.3.1",
"jsonminify": "^0.4.1",
"mini-css-extract-plugin": "^0.4.1",
"node-sass": "^4.9.3",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5",
"webpack-subresource-integrity": "^1.1.0-rc.4",
"webpackbar": "^2.6.3",
"webpack-dashboard": "^2.0.0"
},
"dependencies": {
"jquery": "^3.3.1"
}
}
My config looks like this:
const path = require('path')
const webpack = require('webpack')
const minJSON = require('jsonminify')
const DashboardPlugin = require('webpack-dashboard/plugin');
const plugins = {
progress: require('webpackbar'),
clean: require('clean-webpack-plugin'),
extractCSS: require('mini-css-extract-plugin'),
// extractText: require('extract-text-webpack-plugin'),
sync: require('browser-sync-webpack-plugin'),
sri: require('webpack-subresource-integrity')
}
module.exports = (env = {}, argv) => {
const isProduction = argv.mode === 'production'
let config = {
context: path.resolve('.'),
entry: {
// vendor: [
// '../main/src/main.js'
// ],
app: [
'../main_app/src/style.scss',
'../main_app/src/main.js'
]
},
output: {
path: path.resolve('../main_dist'),
publicPath: '/resources',
filename: 'bundle.js',
crossOriginLoading: 'anonymous'
},
module: {
rules: [
{
test: /\.((s[ac]|c)ss)$/,
use: [
plugins.extractCSS.loader,
{
loader: 'css-loader',
options: {
sourceMap: ! isProduction
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: ! isProduction,
plugins: (() => {
return isProduction ? [
require('autoprefixer')(),
require('cssnano')({
preset: ['default', {
minifySelectors: false
}]
})
] : []
})()
}
},
{
loader: 'sass-loader',
options: {
outputStyle: 'expanded',
sourceMap: ! isProduction
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env'
]
}
}
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
exclude: /fonts/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
publicPath: '..' // use relative urls
}
},
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: ! isProduction,
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
}
}
}
]
},
{
test: /.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
exclude: /images/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
publicPath: '../main_dist/fonts/' // use relative urls
}
}]
}
]
},
devServer: {
contentBase: path.join('../main_app', 'src'),
port: 3000,
overlay: {
warnings: true,
errors: true
},
quiet: true,
// open: true
},
plugins: (() => {
let common = [
new plugins.extractCSS({
filename: '[name].css'
}),
new plugins.progress({
color: '#5C95EE'
})
]
const production = [
new plugins.clean(['dist']),
new plugins.sri({
hashFuncNames: ['sha384'],
enabled: true
})
]
const development = [
new plugins.sync(
{
host: 'localhost',
port: 3000,
proxy: 'http://localhost:3000/'
},
{
reload: true
}
),
//auto updating on dev server
new webpack.HotModuleReplacementPlugin(),
//shows relative path in HotModuleReplacement
new webpack.NamedModulesPlugin(),
//sexy dashboard
new DashboardPlugin()
]
return isProduction
? common.concat(production)
: common.concat(development)
})(),
devtool: (() => {
return isProduction
? '' // 'hidden-source-map'
: 'source-map'
})(),
resolve: {
modules: [
'node_modules',
path.resolve('../main_app/node_modules'),
path.resolve('../node_modules'),
path.resolve('../main/node_modules')
],
alias: {
// '~': path.resolve(__dirname, 'src/scripts/'),
site: path.resolve(`./../../`),
base: path.resolve(`../main/src/`),
app: path.resolve(`../main_app/src/`),
'jquery': 'jquery/dist/jquery',
'jQuery': 'jquery/dist/jquery'
}
}
}
return config
};
I want to achieve two things:
- browser hotloading. I am not sure exactly how this works. I can see all the cool stuff at http://localhost:3001/ but I have no idea how it works. I tried to add this:
//auto updating on dev server
new webpack.HotModuleReplacementPlugin(),
//shows relative path in HotModuleReplacement
new webpack.NamedModulesPlugin(),
but that does not work. I basically want the CSS / JS to update as soon as I save the source file.
As you may have noticed I am a webpack novice!
- I want to set up a output of the CSS in two files:
app.css
and a editor.css
. The latter should contain only selected styles (includes) from my src folder.
Other things to note:
- I don't really understand what
browser sync
actually does, even though it looks impressive
- I like to add the webpack dashboard, it is not a must, but it seemed to help me in the past.
It would be great if you can give me some hints.
The reason I want all this is to put it into this module: https://github.com/sunnysideup/silverstripe-sswebpack_engine_only. I am working on small projects with an environmental slant, such as https://ngaru.com
If you can help then that would be great.
Thank you
Nicolaas