7mpy
@7mpy

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Node.jsでJavaScriptをimportするには?ReferenceError: XXXX is not defined

解決したいこと

Node.jsでJavaScriptをimportする。script.jsでexportを記述せずにMyClassをインポートしたいです。目的は、ブラウザで動作するJavaScriptをテストするためです。なのでexportみたいなNode.jsの記述を入れたくないです。eval()も試しましたがダメダメでした。

発生している問題・エラー

script.js
class MyClass {
  hello() {
    return 'こんにちは'
  }
}
main.mjs
import './script.js'
import assert from 'assert'

console.log(MyClass)

describe('JavaScriptのテスト', function() {
  it('あいさつ出来ること', function() {
    const myClass = new MyClass()
    assert.equal(myClass.hello(), 'こんにちは')
  })
})

エラー内容

$ node main.mjs 
file:///workspaces/KiZooNa.js/main.mjs:3
console.log(MyClass)
            ^

ReferenceError: MyClass is not defined
    at file:///workspaces/KiZooNa.js/main.mjs:3:13
    at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:323:24)
    at async loadESM (node:internal/process/esm_loader:28:7)
    at async handleMainPromise (node:internal/modules/run_main:113:12)

Node.js v20.12.2

自分で試したこと

よくわかんにゃい

1

3Answer

一応こんなんがあります.

ブラウザのscriptで動かす前提のものをNodeな環境でテストするのもなんでかは気になりますが,今どきブラウザでもNodeでもESModuleが使えるのでそのうちこんなことしなくてもよくなるかもしれません.

1Like

Comments

  1. @7mpy

    Questioner

    ありがとうございます。スタバの通りevalを使ったのですが無理みたいです😭

    hoge.mjs
    eval('class MyClass {}')
    
    console.log(MyClass)
    
    $ node hoge.mjs 
    file:///workspaces/KiZooNa.js/hoge.mjs:3
    console.log(MyClass)
                ^
    
    ReferenceError: MyClass is not defined
        at file:///workspaces/KiZooNa.js/hoge.mjs:3:13
        at ModuleJob.run (node:internal/modules/esm/module_job:222:25)
        at async ModuleLoader.import (node:internal/modules/esm/loader:323:24)
        at async loadESM (node:internal/process/esm_loader:28:7)
        at async handleMainPromise (node:internal/modules/run_main:113:12)
    
    Node.js v20.12.2
    

    image.png

    また、script.jsでnode.js環境のみexportしようとすると怒られちゃいます😭😭

    image.png

    script.js
    class MyClass {
      hello() {
        return 'こんにちは'
      }
    }
    
    if (typeof window === 'undefined') {
      export {
        MyClass
      }
    }
    
  2. @7mpy

    Questioner

    いったんこれでいっか...

    script.js
    class MyClass {
      hello() {
        return 'こんにちは'
      }
    }
    
    main.mjs
    import { readFileSync } from 'node:fs'
    import assert from 'assert'
    
    eval(readFileSync('script.js') + ';global.MyClass=MyClass')
    console.log(MyClass)
    
    describe('JavaScriptのテスト', function() {
      it('あいさつ出来ること', function() {
        const myClass = new MyClass()
        assert.equal(myClass.hello(), 'こんにちは')
      })
    })
    
  3. @7mpy

    Questioner

    globalに変数毎回定義するのはだるい気がするけど...globalglobalThisにしてもいける...

  4. @7mpy

    Questioner

    こっちの方が、MyClassが未定義ジャマイカの警告でないかも

    main.mjs
    import { readFileSync } from 'node:fs'
    const { MyClass } = await import(`data:text/javascript;base64,${Buffer.from(readFileSync('script.js') + ';export {MyClass}').toString(`base64`)}`)
    import assert from 'assert'
    
    console.log(MyClass)
    
    describe('JavaScriptのテスト', function () {
        it('あいさつ出来ること', function () {
            const myClass = new MyClass()
            assert.equal(myClass.hello(), 'こんにちは')
        })
    })
    
  5. @7mpy

    Questioner

  6. @7mpy

    Questioner

    どちらにせよ。毎回エクスポートする変数を指定するのはだるい。自動で全部エクスポートしてほしい

  7. @7mpy
    デフォルト private みたいなものなので 公開したいものは頭に export つければいいだけなのでは……?

    function C {}
    const v = 1;
    

    export function C {}
    export const v = 1;
    

    import も

    import * as MyClasses from "./path.js";
    
  8. @7mpy

    Questioner

    なるほど!でも、<script type="module" src="script.js"></script>みたいにtype="module"つけないといけないのは若干抵抗がある気がする

  9. @7mpy

    Questioner

    from XXXXXXXXを動的に作るのはNode.jsではできないっぽいぉ

    main.mjs
    import { readFileSync } from 'node:fs'
    import { MyClass } from `data:text/javascript;base64,${Buffer.from(readFileSync('script.js') + ';export {MyClass}').toString(`base64`)}`
    import assert from 'assert'
    
    console.log(MyClass)
    
    describe('JavaScriptのテスト', function () {
        it('あいさつ出来ること', function () {
            const myClass = new MyClass()
            assert.equal(myClass.hello(), 'こんにちは')
        })
    })
    

Comments

  1. @7mpy

    Questioner

    なるほど!その手があったかっ!でもテストするだけのためにグローバル汚染いやです(すっとぼけ

    @juner
    でも最適解な気はしますね...

    script.js
    class MyClass {
        hello() {
            return 'こんにちは'
        }
    }
    
    globalThis.MyClass = MyClass
    
    test/main.mjs
    import '../script.js'
    import assert from 'assert'
    
    console.log(MyClass)
    
    describe('JavaScriptのテスト', function() {
      it('あいさつ出来ること', function() {
        const myClass = new MyClass()
        assert.equal(myClass.hello(), 'こんにちは')
      })
    })
    

    image.png

  2. 嫌 なら public 修飾子つける感覚で export つけましょう

  3. @7mpy

    Questioner

    hahaha

  4. @7mpy

    Questioner

    Node.js環境のときだけ、晒すでもいいのかなと。。。動作未確認

    script.js
    class MyClass {
        hello() {
            return 'こんにちは'
        }
    }
    
    if (typeof global === 'object') global.MyClass = MyClass
    

これってexportしないとimportできないんですよね~

script.js
export class MyClass {
  hello() {
    return 'こんにちは'
  }
}

また、さっきのようにインポートするだけだとグローバルコードだけ実行されて何もインポートしないです。

なのでこのように変えましょう。

main.mjs
import {MyClass} from './script.js'
import assert from 'assert'

console.log(MyClass)

describe('JavaScriptのテスト', function() {
  it('あいさつ出来ること', function() {
    const myClass = new MyClass()
    assert.equal(myClass.hello(), 'こんにちは')
  })
})

これが正しいインポートじゃないですかね。

0Like

Your answer might help someone💌