LinbuduLab / esbuild-plugins

ESBuild plugins by @LinbuduLab
MIT License
113 stars 18 forks source link

Cannot use import statement outside a module #56

Closed pjdevries closed 2 years ago

pjdevries commented 2 years ago

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?

linbudu599 commented 2 years ago

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';
pjdevries commented 2 years ago

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?

linbudu599 commented 2 years ago

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

pjdevries commented 2 years ago

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.

linbudu599 commented 2 years ago

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.

pjdevries commented 2 years ago

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.