[Laracasts.com] Webpack for Everyone [ENG, 2017]



Looks like that video for free:
https://laracasts.com/series/webpack-for-everyone

MySRC (many branches):
https://bitbucket.org/marley-nodejs/webpack-for-everyone/


Prepare Environment


$ mkdir -p /projects/js/webpack/webpack-for-everyone/


$ docker run -it \
-p 80:8080 -p 1337:1337 -p 3000:3000 -p 4000:4000 -p 5000:5000 -p 6000:6000 -p 7000:7000 -p 8000:8000 -p 9000:9000 \
--name webpack-for-everyone \
-v /projects/js/webpack/webpack-for-everyone/:/project \
node \
/bin/bash


# apt-get update
# apt-get install -y vim git


01-Zero-Config-Webpack-Compilation

# cd /project
# npm init -y

$ npm i -g webpack


-- ("webpack": "^2.6.1")
# npm install --save-dev webpack


# mkdir -p src
# vi src/main.js


alert('main');


# vi index.html


<html>
    <head>
        <title></title>
    </head>


<body>

    <h1>Hello World!</h1>


    <script src="dist/bundle.js"></script>

</body>


</html>


# vi package.json

"scripts": {
    "build": "webpack src/main.js dist/bundle.js",
    "watch": "npm run build -- --watch"
  },


 # npm run build
 # npm run watch


02-A-Dedicated-Configuration-File

# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

module.exports = {

    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    }

};


# vi package.json

"scripts": {
    "build": "webpack",
    "watch": "npm run build -- --watch"
  },


# npm run build
# npm run watch


03-Modules-Are-Just-Files


# vi src/main.js


import notification from './Notification';

notification.log('here we go');
notification.announce('here we go as an alert');



# vi src/Notification.js


function announce (message) {
    alert(message);
}

function log (message) {
    console.log(message);
}

export default {
    announce: announce,
    log: log
};



# npm run watch


04-Loaders-Are-Transformers


# npm install --save-dev css-loader
# npm install --save-dev style-loader


# vi src/main.js


require('./main.css');


# vi src/main.css


# vi src/main.css


body {
    background: red;
}


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

module.exports = {

    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
};


# npm run build


05-ES2015-Compilation-With-Babel

http://babeljs.io/docs/setup/#installation

# npm install --save-dev babel-loader babel-core

http://babeljs.io/docs/plugins/

# npm install --save-dev babel-cli babel-preset-es2015


# echo '{ "presets": ["es2015"] }' > .babelrc


# vi src/main.js


class Form {
    constructor(){
        alert('Yay Form classes are great no matter what JS developers say!');

        let numbers = [5, 10, 15].map(number => number * 2);

        console.log(numbers);
    }
}


new Form();


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

module.exports = {

    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    }
};


# npm run build


06-Minification-and-Environments


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: './src/main.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [


    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# vi package.json


"scripts": {
    "dev": "webpack",
    "prod": "NODE_ENV=production webpack",
    "watch": "npm run build -- --watch"
},


# npm run dev
# npm run prod


07-Sass-Compilation

# npm install --save-dev sass-loader node-sass


# vi src/main.js


require('./main.scss');


# vi src/main.scss


$primary: green;

body {
    background: $primary;
}


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

entry: './src/main.js',
output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
},

module: {
    rules: [
        {
            test: /\.s[ac]ss$/,
            use: ['style-loader', 'css-loader', 'sass-loader']
        },

        {
            test: /\.css$/,
            use: ['style-loader', 'css-loader']
        },

        {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: "babel-loader" }
    ]
},

plugins: [


]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


08-Extract-CSS-To-A-Dedicated-File

https://github.com/webpack-contrib/extract-text-webpack-plugin

# npm install --save-dev extract-text-webpack-plugin

https://webpack.js.org/plugins/loader-options-plugin/


# vi src/main.js


alert('empty');


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

const ExtractTextPlugin = require("extract-text-webpack-plugin");

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },

    module: {
        rules: [
            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },


            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [
        new ExtractTextPlugin('[name].css'),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
            })

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev
# npm run prod


09-The-Relative-CSS-Url-Conundrum

https://github.com/webpack-contrib/css-loader


# npm install --save-dev file-loader


# vi src/main.scss


.test {
    background: url('./images/cat.jpg');
}


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');

const ExtractTextPlugin = require("extract-text-webpack-plugin");

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },

    module: {
        rules: [
            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },

            {
                test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'file-loader',
                options: {
                    name: 'images/[name].[hash].[ext]'
                }
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [
        new ExtractTextPlugin('[name].css'),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
            })

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


10-Strip-Unused-CSS-Automatically

https://github.com/webpack-contrib/purifycss-webpack


# npm i -D purifycss-webpack purify-css


# vi index.html


<html>
    <head>
        <title></title>
    </head>


<body>

    <h1>Hello World!</h1>

    <div class="two">Hello</div>


    <script src="dist/bundle.js"></script>

</body>


</html>


# vi src/main.scss


.one {
    background: red;
}

.two {
    background: green;
}


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');
const glob = require('glob');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require('purifycss-webpack');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },

    module: {
        rules: [
            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },

            {
                test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'file-loader',
                options: {
                    name: 'images/[name].[hash].[ext]'
                }
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [
        new ExtractTextPlugin('[name].css'),

        new PurifyCSSPlugin({
         // paths: glob.sync(path.join(__dirname, 'app/*.html')),
         paths: glob.sync(path.join(__dirname, 'index.html')),

         minimize: inProduction

        }),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
        })

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


11-File-Hashing

# npm install jquery -D

https://github.com/johnagan/clean-webpack-plugin

# npm install --save-dev clean-webpack-plugin


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');
const glob = require('glob');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require('purifycss-webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss'],
        vendor: ['jquery']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[chunkhash].js'
    },

    module: {
        rules: [
            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },

            {
                test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'file-loader',
                options: {
                    name: 'images/[name].[hash].[ext]'
                }
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [

        new CleanWebpackPlugin(['dist']),

        new ExtractTextPlugin('[name].css'),

        new PurifyCSSPlugin({
         // paths: glob.sync(path.join(__dirname, 'app/*.html')),
         paths: glob.sync(path.join(__dirname, 'index.html')),

         minimize: inProduction

        }),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
        })

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


12-Webpack-Manifests


# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');
const glob = require('glob');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require('purifycss-webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss'],
        vendor: ['jquery']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[chunkhash].js'
    },

    module: {
        rules: [
            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },

            {
                test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,
                loader: 'file-loader',
                options: {
                    name: 'images/[name].[hash].[ext]'
                }
            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [

        new CleanWebpackPlugin(['dist']),

        new ExtractTextPlugin('[name].css'),

        new PurifyCSSPlugin({
         // paths: glob.sync(path.join(__dirname, 'app/*.html')),
         paths: glob.sync(path.join(__dirname, 'index.html')),

         minimize: inProduction

        }),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
        }),

        function(){
            this.plugin('done', stats => {
                require('fs').writeFileSync(
                    path.join(__dirname, 'dist/mainfest.json'),
                    JSON.stringify(stats.toJson().assetsByChunkName)
                );
            });
        }

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


13-Automatic-Image-Optimization

https://github.com/thetalecrafter/img-loader

# npm install --save-dev img-loader



# vi webpack.config.js


var webpack = require('webpack');
const path = require('path');
const glob = require('glob');

const ExtractTextPlugin = require("extract-text-webpack-plugin");
const PurifyCSSPlugin = require('purifycss-webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');

var inProduction = (process.env.NODE_ENV === 'production');

module.exports = {

    entry: {
        app: ['./src/main.js',
             './src/main.scss'],
        vendor: ['jquery']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].[chunkhash].js'
    },

    module: {
        rules: [

            {
                test: /\.css$/,
                use: 'css-loader'
            },

            {
                test: /\.s[ac]ss$/,
                use: ExtractTextPlugin.extract({
                    use: ['css-loader', 'sass-loader'],
                    fallback: 'style-loader'
                })
            },

            {
                test: /\.(png|jpe?g|gif|svg|eot|ttf|woff|woff2)$/,

                loaders: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'images/[name].[hash].[ext]'
                        }
                    },

                    'img-loader'
                ]

            },

            {
                test: /\.js$/,
                exclude: /node_modules/,
                loader: "babel-loader" }
        ]
    },

    plugins: [

        new CleanWebpackPlugin(['dist']),

        new ExtractTextPlugin('[name].css'),

        new PurifyCSSPlugin({
         // paths: glob.sync(path.join(__dirname, 'app/*.html')),
         paths: glob.sync(path.join(__dirname, 'index.html')),

         minimize: inProduction

        }),

        new webpack.LoaderOptionsPlugin({
              minimize: inProduction
        }),

        function(){
            this.plugin('done', stats => {
                require('fs').writeFileSync(
                    path.join(__dirname, 'dist/mainfest.json'),
                    JSON.stringify(stats.toJson().assetsByChunkName)
                );
            });
        }

    ]
};

if (inProduction){
    module.exports.plugins.push(
        new webpack.optimize.UglifyJsPlugin()
    );
}


# npm run dev


14-Developing-Webpack-Plugins