LinbuduLab/esbuild-plugins

Cannot use import statement outside a module

pjdevries opened this issue · 6 comments

Hi. Please accept my apologies beforehand, for my lack of knowledge and experience.

I'm trying to use the esbuild-plugin-copy plugin, to copy several files to their final destinations, after esbuild has done its thing. For that purpose I have a simple build.js script, which I execute from my equally simple package.json like so:

"scripts": { "build": "node --trace-warnings build.js" }.

The build.js script itself roughly looks like this:

import copy from 'esbuild-plugin-copy';

require('esbuild').build({
    entryPoints: [
        ...
    ],
    loader: {
        ...
    },
    bundle: true,
    outdir: 'dist',
    plugins: [
        copy({
            assets: {
                from: ['./dist/*.js'],
                to: ['../assets/js'],
            },
        }),
        copy({
            assets: {
                from: ['./dist/*.css'],
                to: ['../assets/css'],
            },
        })
    ]
}).catch(() => process.exit(1))

Without the import and plugins sections, the script runs fine and produces the desired output files. However, when including the import and plugins sections, I get the following error:

import copy from 'esbuild-plugin-copy';
^^^^^^

SyntaxError: Cannot use import statement outside a module

My extremely limited knowledge tells me I'm mixing CommonJS and ES6 modules here. The problem is I don't know how to fix it. I have tried var copy = require('esbuild-plugin-copy'), but that does not work.

How can I get the copy function to work in my build script?

To use ES Module in .js file, you will need to rename file with .mjs ext, and add type: 'module' in your package.json, then you can execute it by node build.mjs.
Also, by doing this, you cannot use require any more, just change it to:

import copy from 'esbuild-plugin-copy';
import { build } from 'esbuild';

Thanx for the reply @linbudu599.

I did like you said. My package.json now roughly looks like this:

{
  "dependencies": {
    ...
  },
  "type": "module",
  "scripts": {
    "build": "node build.mjs"
  },
  "devDependencies": {
    "esbuild": "^0.13.15",
    "esbuild-plugin-copy": "^0.2.0"
  }
}

and my build.mjs file like this:

import { build } from 'esbuild';
import copy from 'esbuild-plugin-copy';

build({
    entryPoints: [
        ...
    ],
    loader: {
        ...
    },
    bundle: true,
    outdir: 'dist',
    plugins: [
        copy({
            assets: {
                from: ['./dist/*.js'],
                to: ['../assets/js'],
            },
        }),
        copy({
            assets: {
                from: ['./dist/*.css'],
                to: ['../assets/css'],
            },
        })
    ]
}).catch(() => process.exit(1))

The import error has disappeared, but I now get

copy({
^

TypeError: copy is not a function

Any clues what might still go wrong?

Use copy.default() instead, because this package is built as CommonJS. (For applicability, as ESM can import CJS, CJS cannot import ESM)

I update the plugin to version 0.3.0 and now use copy.default() as you suggested. No more error messages :) The files are copied, but unfortunately not into the right folder.

As you can see above, the to: paths are relative, with the assumption that they are relative to the current folder (i.e. the folder where package.json resides). I expect the files to be copied to a sub folder of the parent, but they are copied into a sub folder of the current folder instead. Consider the following folder structure:

/some/path/3rdParty
    package.json
    ../src
    ../dist
/some/path/com_dma
    ../js
    ../css

In this scenario, I assume /some/path/3rdParty to be the current folder. I would expect the files to be copied from /some/path/3rdParty/dist to /some/path/com_dma/js and /some/path/com_dma/css. Instead they are copied to /some/path/3rdParty/com_dma/js and /some/path/3rdParty/com_dma/css.

So it seems the plugin copies the files relative to their original locations, as opposed to relative to the current folder, which feels somewhat counterintuitive Is that assumption correct and if so, is it by design or is it a mistake? In any case, it would be helpful to include a pointer in the documentation.

to path is calculated based on otudir or outfil from your esbuild options(and from path based on cwd), in your cases it's resolved from root/current/dist, so using ../assets as to path indicates output to root/current/assets. To use root/assets as destination, just specify ../../assets.
Also, I'll add tips in the documentation later.

Thanx for the clarification. It all seems to work fine now.

Thank you also for your time and patience and for making your software freely available to the rest of us.