0

In the command line webpack throws out the following error when I try to execute 'npm run dev' with the following commands:

    "dev": "npm-run-all -p devFast buildWatch",
    "devFast": "webpack serve",
    "buildWatch": "webpack --watch",
    "build": "webpack",

Error:

PS C:\wamp64\www\workshop_01\wp-content\themes\workshop_01> npm run dev

> [email protected] dev C:\wamp64\www\workshop_01\wp-content\themes\workshop_01
> npm-run-all -p devFast buildWatch


> [email protected] devFast C:\wamp64\www\workshop_01\wp-content\themes\workshop_01
> webpack serve


> [email protected] buildWatch C:\wamp64\www\workshop_01\wp-content\themes\workshop_01
> webpack --watch

[webpack-cli] Failed to load 'C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\webpack.config.js' config
[webpack-cli] TypeError: ManifestPlugin is not a constructor
    at Object.<anonymous> (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\webpack.config.js:124:115)
    at Module._compile (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1097:10)
    at Module.load (internal/modules/cjs/loader.js:933:32)
    at Function.Module._load (internal/modules/cjs/loader.js:774:14)
    at Module.require (internal/modules/cjs/loader.js:957:19)
    at require (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\node_modules\v8-compile-cache\v8-compile-cache.js:159:20)
    at WebpackCLI.tryRequireThenImport (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\node_modules\webpack-cli\lib\webpack-cli.js:32:22)
    at loadConfig (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\node_modules\webpack-cli\lib\webpack-cli.js:1536:38)
    at WebpackCLI.resolveConfig (C:\wamp64\www\workshop_01\wp-content\themes\workshop_01\node_modules\webpack-cli\lib\webpack-cli.js:1639:44)
npm ERR! code ELIFECYCLE
npm ERR! errno 2
npm ERR! [email protected] buildWatch: `webpack --watch`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the [email protected] buildWatch script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\BudWiser\AppData\Roaming\npm-cache\_logs\2021-06-13T09_23_22_025Z-debug.log
ERROR: "buildWatch" exited with 2.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev: `npm-run-all -p devFast buildWatch`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

package.json

{
  "name": "workshop_01",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "npm-run-all -p devFast buildWatch",
    "devFast": "webpack serve",
    "buildWatch": "webpack --watch",
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@babel/core": "^7.14.5",
    "@babel/preset-env": "^7.14.5",
    "@babel/preset-react": "^7.14.5",
    "@glidejs/glide": "^3.4.1",
    "autoprefixer": "^10.2.6",
    "axios": "^0.21.1",
    "babel-loader": "^8.2.2",
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "css-loader": "^5.2.6",
    "cssnano": "^5.0.6",
    "fs-extra": "^10.0.0",
    "jquery": "^3.6.0",
    "mini-css-extract-plugin": "^1.6.0",
    "normalize.css": "^8.0.1",
    "npm-run-all": "^4.1.5",
    "postcss-color-function": "^4.1.0",
    "postcss-hexrgba": "^2.0.1",
    "postcss-import": "^14.0.2",
    "postcss-loader": "^6.1.0",
    "postcss-mixins": "^8.1.0",
    "postcss-nested": "^5.0.5",
    "postcss-simple-vars": "^6.0.3",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "style-loader": "^2.0.0",
    "webpack": "^5.38.1",
    "webpack-cli": "^4.7.2",
    "webpack-dev-server": "^3.11.2",
    "webpack-manifest-plugin": "^3.1.1"
  }
}

webpack.config.js

/*
  SUPER IMPORTANT: This config assumes your theme folder is named
  exactly 'fictional-university-theme' and that you have a folder
  inside it named 'bundled-assets' - If you'd like to adapt this
  config to work with your own custom folder structure and names
  be sure to adjust the publicPath value on line #116. You do NOT
  need to update any of the other publicPath settings in this file,
  only the one on line #116.
*/

const currentTask = process.env.npm_lifecycle_event
const path = require("path")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const ManifestPlugin = require("webpack-manifest-plugin")
const fse = require("fs-extra")

const postCSSPlugins = [require("postcss-import"), require("postcss-mixins"), require("postcss-simple-vars"), require("postcss-nested"), require("postcss-hexrgba"), require("postcss-color-function"), require("autoprefixer")]

class RunAfterCompile {
  apply(compiler) {
    compiler.hooks.done.tap("Update functions.php", function () {
      // update functions php here
      const manifest = fse.readJsonSync("./bundled-assets/manifest.json")

      fse.readFile("./functions.php", "utf8", function (err, data) {
        if (err) {
          console.log(err)
        }

        const scriptsRegEx = new RegExp("/bundled-assets/scripts.+?'", "g")
        const vendorsRegEx = new RegExp("/bundled-assets/vendors.+?'", "g")
        const cssRegEx = new RegExp("/bundled-assets/styles.+?'", "g")

        let result = data.replace(scriptsRegEx, `/bundled-assets/${manifest["scripts.js"]}'`).replace(vendorsRegEx, `/bundled-assets/${manifest["vendors~scripts.js"]}'`).replace(cssRegEx, `/bundled-assets/${manifest["scripts.css"]}'`)

        fse.writeFile("./functions.php", result, "utf8", function (err) {
          if (err) return console.log(err)
        })
      })
    })
  }
}

let cssConfig = {
  test: /\.css$/i,
  use: ["css-loader?url=false", { loader: "postcss-loader", options: { plugins: postCSSPlugins } }]
}

let config = {
  entry: {
    scripts: "./js/scripts.js"
  },
  plugins: [],
  module: {
    rules: [
      cssConfig,
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-react", ["@babel/preset-env", { targets: { node: "12" } }]]
          }
        }
      }
    ]
  }
}

if (currentTask == "devFast") {
  config.devtool = "source-map"
  cssConfig.use.unshift("style-loader")
  config.output = {
    filename: "bundled.js",
    publicPath: "http://localhost:3000/"
  }
  config.devServer = {
    before: function (app, server) {
      /*
        If you want the browser to also perform a traditional refresh
        after a save to a JS file you can modify the line directly
        below this comment to look like this instead. I'm using this approach
        instead of just disabling Hot Module Replacement beacuse this way our
        CSS updates can still happen immediately without a page refresh.
        If you're using a slower computer and the new bundle is not ready
        by the time this is reloading the browser you can always just set the 
        "hot" property a few lines below this to false instead of true. That
        will work on all computers and the only trade off is the browser will
        perform a traditional refresh even for CSS changes as well.
        */

      // server._watch(["./**/*.php", "./**/*.js"])
      server._watch(["./**/*.php", "!./functions.php"])
    },
    public: "http://localhost:3000",
    publicPath: "http://localhost:3000/",
    disableHostCheck: true,
    contentBase: path.join(__dirname),
    contentBasePublicPath: "http://localhost:3000/",
    hot: true,
    port: 3000,
    headers: {
      "Access-Control-Allow-Origin": "*"
    }
  }
  config.mode = "development"
}

if (currentTask == "build" || currentTask == "buildWatch") {
  cssConfig.use.unshift(MiniCssExtractPlugin.loader)
  postCSSPlugins.push(require("cssnano"))
  config.output = {
    publicPath: "/wp-content/themes/workshop_01/bundled-assets/",
    filename: "[name].[chunkhash].js",
    chunkFilename: "[name].[chunkhash].js",
    path: path.resolve(__dirname, "bundled-assets")
  }
  config.mode = "production"
  config.optimization = {
    splitChunks: { chunks: "all" }
  }
  config.plugins.push(new CleanWebpackPlugin(), new MiniCssExtractPlugin({ filename: "styles.[chunkhash].css" }), new ManifestPlugin({ publicPath: "" }), new RunAfterCompile())
}

module.exports = config

scripts.js

import "../css/style.css"

// Allow new JS and CSS to load in browser without a traditional page refresh
if (module.hot) {
  module.hot.accept()
}

enter image description here

When I type the command, npm run devFast, that successfully compiles.

Can anyone see what the problem is? I can see that there is an issue with something to do with config in webpack.config.js, but stumped what it means.

I tried to search this particular error, but I didn't find anything that was closely related this issue...

1 Answer 1

1

The error you get is:

[webpack-cli] TypeError: ManifestPlugin is not a constructor

You are trying to load weback-manifest-plugin it like this:

const ManifestPlugin = require("webpack-manifest-plugin")

How it should be loaded

Looking at the documentation for webpack-manifest-plugin, it should be loaded like this:

const { WebpackManifestPlugin } = require('webpack-manifest-plugin');

So change that row, and then also replace:

new ManifestPlugin({ publicPath: "" })

with:

new WebpackManifestPlugin({ publicPath: "" })

Now it should work!

The bigger problem

I see that you are loading everything as dependencies, while most of them should be loaded as devDependencies.

A dependency is something that will be bundled in your code, and loaded by the browser who visits your website.

A dev dependency is something that you are using in your build process, and it's not being bundled with the JS that ends up on your website.

Think of devDependencies as software tools you use to build the website. Almost the same way as VS Code or whatever editor you are using. It's software needed for the project, but every visitor to your website does not need to download VS Code to their computer just to view your website.

These are some of the libraries that should be devDependencies:

  • @babel/core
  • @babel/preset-env
  • @babel/preset-react
  • autoprefixer

Most of them have this written in the documentation. See: https://github.com/postcss/autoprefixer#using-environment-variables-to-support-css-grid-prefixes-in-create-react-app

The installation instructions say:

npm install autoprefixer@latest cross-env --save-dev

The --save-dev flag is what puts it in devDependencies rather than dependencies. This will have a big effect on the bundle size when you are building the project.

Read more on npmjs.com, about dependencies and devDependencies.

The other big problem

You are loading things such as axios, jquery, normalize.css. When you bundle them like this, WordPress is unaware they they are bundled, and if you are using a plugin that also needs jquery, that plugin will load jquery one extra time. This can lead to errors for the user.

Instead you should use wp_enqueue_script for anything that WordPress should be aware of.

By using this function, you can tell WordPress what version of a dependency you are loading, and other scripts that might be depending on that library can have that as a dependancy, making sure things load in the right way, and only once.

There is a really nice guide on how to include CSS and JavaScript in WordPress. Bundle your own JS and CSS, and enqueue those using the correct WordPress functions, but any external libraries, such as jQuery, axios, glide etc, add them in a way so that WordPress is aware of them.

5
  • In regards to your first answer, I did initially try this though, I just didn't think to add the curly braces around WebpackManifestPlugin so it didn't obv work, but I was on the right track then lol good to know!
    – Krys
    Commented Jun 13, 2021 at 12:11
  • For your second answer, I see now what you mean and others who have provided examples in their codes with the additional --save dev. I will update that accordingly.
    – Krys
    Commented Jun 13, 2021 at 12:14
  • To your last answer, should I just enqueue axios, jquery, and normalize.css instead of bundling them up as dependencies, is that what you mean? I do have my css and my scripts.js enqueued in wordpress functions.php file.
    – Krys
    Commented Jun 13, 2021 at 12:22
  • 1
    Thanks Fabian, for your explanations, they helped me out a lot! Much appreciated ;)
    – Krys
    Commented Jun 13, 2021 at 12:30
  • Nice to hear, and happy to help! I still remember when this whole build setup felt impossible to grasp for me. If I managed to master it, so will you! A good tip is looking at other projects on GitHub, where you can peak into their package.json, webpack.config.js and other all of these things to see how others do it ✌️ Commented Jun 13, 2021 at 12:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.