Sporego
Sporego

Reputation: 416

Adding CopyPlugin to next.config.js

I want to add the following to my webpack config!

module.exports = {
  ...otherConfig,
  plugins: [
    new CopyPlugin([{ 
        from: './node_modules/@pdftron/webviewer/public',
        to: './dist/public/webviewer' 
      }]
    ),
  ],
};

However, since I'm using Next.js, I follow the docs here: https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config

This is my code that I ended up with:

const CopyPlugin = require("copy-webpack-plugin");

module.exports = {
    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        // Note: we provide webpack above so you should not `require` it
        // Perform customizations to webpack config
        const newconfig = config.plugins.push(
            new CopyPlugin([
                {
                    from: './node_modules/@pdftron/webviewer/public',
                    to: './public/webviewer',
                },
            ]),
        );

        // Important: return the modified config
        return newconfig
    },
}

Why doesn't it work?

This is the error:

ready - started server on http://localhost:3000
ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
 - options[0] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, filter?, toType?, force?, info?, transform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)
    at validate (D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\copy-webpack-plugin\node_modules\schema-utils\dist\validate.js:104:11)
    at new CopyPlugin (D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\copy-webpack-plugin\dist\index.js:40:31)
    at Object.webpack (D:\Code\Javascript\nextjs-projects\new-amsterdam\next.config.js:8:13)
    at getBaseWebpackConfig (D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\next\dist\build\webpack-config.js:136:360)
    at async Promise.all (index 0)
    at async HotReloader.start (D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\next\dist\server\hot-reloader.js:14:2403)
    at async DevServer.prepare (D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\next\dist\server\next-dev-server.js:15:414)
    at async D:\Code\Javascript\nextjs-projects\new-amsterdam\node_modules\next\dist\cli\next-dev.js:22:1 {
  errors: [
    {
      keyword: 'required',
      dataPath: '[0]',
      schemaPath: '#/required',
      params: [Object],
      message: "should have required property 'patterns'",
      schema: [Object],
      parentSchema: [Object],
      data: [Object],
      children: [Array]
    }
  ],
  schema: {
    definitions: { ObjectPattern: [Object], StringPattern: [Object] },
    type: 'object',
    additionalProperties: false,
    properties: { patterns: [Object], options: [Object] },
    required: [ 'patterns' ]
  },
  headerName: 'Copy Plugin',
  baseDataPath: 'options',
  postFormatter: null
}

Thank you in advance!

Upvotes: 8

Views: 14085

Answers (2)

bmdev
bmdev

Reputation: 416

The code in your answer is correct, and I hope I can help to explain why. There were two errors I could see in your original code in question:

1. copy-webpack-plugin was configured incorrectly.

Your original configuration was an array with one object:

new CopyPlugin([
  {
    from: './node_modules/@pdftron/webviewer/public',
    to: './public/webviewer',
  },
]),

But to get the result you wanted, you needed to provide the plugin with a configuration object with the key "patterns" (which contains an array), like you did in your answer:

new CopyPlugin({
  patterns: [
    {
      from: './node_modules/@pdftron/webviewer/public',
      to: './public/webviewer',
    },
  ],
})

The error message you posted in your question explained how the plugin was incorrectly configured, just not in the most intuitive way:

ValidationError: Invalid options object. Copy Plugin has been initialized using an options object that does not match the API schema.
 - options[0] misses the property 'patterns'. Should be:
   [non-empty string | object { from, to?, context?, globOptions?, filter?, toType?, force?, info?, transform?, transformPath?, noErrorOnMissing? }, ...] (should not have fewer than 1 item)

2.The return value of your "webpack" method was incorrect.

In your initial code, you assigned the variable "newconfig" to get the result of config.plugins.push(...), and then returned it:

const newconfig = config.plugins.push(

// ... plugin config ...

// Important: return the modified config
return newconfig

But, as you can see from the MDN docs on Array.push, the return value of Array.push is the length of the array.

Therefore, when you wrote return newconfig, that was like writing return config.plugins.length, when next.js is expecting you to return the entire config object.

When you push an item to an array, the array is modified in place, so you don't need to capture a new value. Therefore, you could simply return the original config:

// Important: return the modified config
return config

The code from your answer, in its entirety, works as it should:

const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        // Note: we provide webpack above so you should not `require` it
        // Perform customizations to webpack config
        config.plugins.push(
            new CopyPlugin({
                patterns: [
                    {
                        from: './node_modules/@pdftron/webviewer/public',
                        to: './public/webviewer',
                    },
                ],
            })
        )

        // Important: return the modified config
        return config
    },
}

I'm not sure why you needed to also uninstall and reinstall the copy-webpack-plugin package unless there's something I'm missing.

Upvotes: 13

Sporego
Sporego

Reputation: 416

This is dumb because I don't understand why this works but...

my new code is this

const CopyPlugin = require('copy-webpack-plugin')

module.exports = {
    webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
        // Note: we provide webpack above so you should not `require` it
        // Perform customizations to webpack config
        config.plugins.push(
            new CopyPlugin({
                patterns: [
                    {
                        from: './node_modules/@pdftron/webviewer/public',
                        to: './public/webviewer',
                    },
                ],
            })
        )

        // Important: return the modified config
        return config
    },
}

AND

I had to run

npm uninstall copy-webpack-plugin --save
npm install [email protected] --save

Now no errors... weird

Upvotes: 1

Related Questions