A
A
Alexander2018-09-03 09:54:31
JavaScript
Alexander, 2018-09-03 09:54:31

How to properly configure webpack4 to work with pug?

Greetings. I want to completely abandon gulp in favor of webpack, but when setting it up, I didn’t understand why webpack-dev-server doesn’t see the generated html files?

Project structure
/
    node_modules
    public_html
    source
        legacy
            files
            js
            pug
            scss
            svg            
        new
            ...
    webpack.config.js

package.json/scripts
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "clean": "del-cli public_html\\assets public_html\\fav* public_html\\*.html -f",
    "prebuild": "npm run clean",
    "build": "webpack --mode production --colors --progress",
    "prestart": "npm run clean",
    "start": "webpack-dev-server --mode development --hot --colors --progress"
  },

webpack.config.js
const
  path = require('path'),
  fs = require('fs'),
  argv = require('yargs').argv,
  CopyWebpackPlugin = require('copy-webpack-plugin'),
  UglifyJsPlugin = require('uglifyjs-webpack-plugin'),
  MiniCssExtractPlugin = require('mini-css-extract-plugin'),
  OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'),
  HtmlWebpackPugPlugin = require('html-webpack-pug-plugin'),
  HtmlWebpackPlugin = require('html-webpack-plugin'),
  HashWebpackPlugin = require('hash-webpack-plugin'),
  WebpackChunkHash = require('webpack-chunk-hash');

const
  development = argv.mode === 'development',
  production = !development,
  mode = production ? 'production' : 'development',
  dest = path.join(__dirname, 'public_html'),
  assets = path.join(dest, 'assets'),
  src = path.resolve(__dirname, 'source'),
  node_modules = path.resolve(__dirname, 'node_modules');

const entries = {
  legacy: {
      'main': [
        '@babel/polyfill',
        './js/main.js'
      ],
      'jquery.selectric': node_modules + '/selectric/public/jquery.selectric.js'
      // ...
  }  
};

const 
  optimization = {
    minimizer: [
      new UglifyJsPlugin({
        sourceMap: true,
        uglifyOptions: {
          compress: {
            inline: false,
            warnings: false,
            drop_console: true,
            unsafe: true
          },
        },
      }),
      new OptimizeCSSAssetsPlugin({})
    ],
  },
  rules = [
    {
      test: /\.scss$/,
      use: [
        development ? 'style-loader' : MiniCssExtractPlugin.loader,
        {
          loader: 'css-loader',
          options: {
            minimize: production,
            url: false
          }
        },
        {
          loader: 'postcss-loader',
          options: {
            ident: 'postcss',
            plugins: [
              require('autoprefixer')({
                browsers: [
                  "last 4 version",
                  "ie 11"
                ],
              })
            ]
          }
        },
        'sass-loader'
      ]
    },
    {
      test: /\.js$/,
      exclude: /node_modules/,
      use: [
        {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env'],
            plugins: [
              '@babel/plugin-syntax-dynamic-import',
              '@babel/plugin-transform-runtime'
            ]
          }
        }
      ]
    }
  ],
  stats = {
    children: false, 
    assets: false,
    colors: true,
    version: false,
    hash: true,
    timings: true,
    chunks: false,
    chunkModules: false
  };

const ls = (dir, regexp = /\.pug/) => 
  fs.readdirSync(dir)
    .reduce((files, file) =>
      fs.statSync(path.join(dir, file)).isDirectory() ?
          files.concat(ls(path.join(dir, file), regexp)) :   
          (path.join(dir, file).match(regexp) ?       
            files.concat(path.join(dir, file)) : files
          ), 
      []
    );

let legacyPlugins = [];
ls(path.join(src, 'legacy', 'pug', 'pages')).forEach((fn) => legacyPlugins.push(
  new HtmlWebpackPlugin({
    template: fn,
    inject: false,
    filename: path.resolve(
      dest, 
      'legacy-' + path.basename(fn, '.pug').replace('/', '-') + '.html'
    )
  })
));

legacyPlugins.push(new HtmlWebpackPugPlugin());
if (production) {
  legacyPlugins.push(new HashWebpackPlugin({
    path: assets,
    'fileName': '.version'
  }));
}

ls(path.join(src, 'legacy', 'scss'), /\\[a-z0-9\-\.]+\.scss/).forEach((fn) => {
  let basename = path.basename(fn, '.scss'),
      name = path.basename(fn);
  entries.legacy[basename] = './scss/' + name;
});

let config = [ 
  {
    name: 'legacy',
    mode: mode,
    entry: entries.legacy,
    output: {
      publicPath: '/',
      filename: 'js/[name].js',      
      chunkFilename: 'js/[name].[chunkhash].js',
      path: path.join(assets, 'legacy'),
    },
    context: path.resolve(src, 'legacy'),
    module: {
      rules: rules.concat([{
        test: /\.pug$/,
        exclude: /node_modules/,
        use: [
          'html-loader',
          {
            loader: 'pug-html-loader',
            options: {
              pretty: production,
              data: require(path.resolve(src, 'legacy', 'demo.json'))
            }
          }
        ]
      }])
    },
    optimization: production ? optimization : {},      
    plugins: legacyPlugins.concat([
      new CopyWebpackPlugin(
        [
          {
            from: path.join(src, 'legacy', 'files'),
            to: dest,
            force: true
          },
          {
            from: path.join(src, 'legacy', 'svg'),
            to: path.join(assets, 'legacy', 'svg'),
            force: true
          }
        ], 
        { copyUnmodified: true }
      ),
      new MiniCssExtractPlugin({
        filename: 'css/[name].css',
        chunkFilename: "css/[id].css"
      }),
      new WebpackChunkHash({algorithm: 'md5'}),
      new webpack.HotModuleReplacementPlugin()
    ]),
    externals: {
      jquery: 'jQuery'
    },
    stats: stats,
    devServer: {
      contentBase: dest,
      publicPath: '',    
      port: 9000,
      compress: true,
      open: true,
      hot: true
    }
  }
];

module.exports = config;
Console
Child html-webpack-plugin for "..\..\legacy-404.html":
         1 asset
        Entrypoint html-webpack-plugin for "..\..\legacy-404.html" = ..\..\legacy-404.html
        [../../node_modules/html-webpack-plugin/lib/loader.js!./pug/pages/tech/404.pug] D:/Project/website/node_modules/html-webpack-plugin/lib/loader.js!./pug/pages/tech/404.pug 7.1 KiB {html-webpack-plugin for "..\..\legacy-404.html"} [built]

Of course, more information is displayed in the console, but it is related to the assembly of js and css. Without webpack-dev-server, everything is going to work, but, of course, it's hard to work.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander, 2018-09-04
@codemafia

The minimal configuration works, but hrm doesn't automatically update the html (which makes sense). Most likely wiser with the paths in the original settings.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question