k88hudson / babel-plugin-jsm-to-esmodules

MIT License
2 stars 2 forks source link

Documentation: plugin integration in an extension #5

Open kael opened 4 years ago

kael commented 4 years ago

Writing a Thunderbird extension, been looking for a way to test (non-XPCOM-based) .jsm modules using nodejs. And it seems using the babel-plugin-jsm-to-esmodules could help by converting JSM modules exports into ES ones.

Not sure how to integrate the plugin in a project and to generate an alternate output.

Would you please add an example on how to generate ES modules in a output directories ?

Cheers.

Mardak commented 4 years ago

Here's an example usage of this plugin:

https://github.com/mozilla/activity-stream/blob/23a4dca949ebeffd80b749672f08ee40ffa27f99/webpack.system-addon.config.js#L46

that converts jsm into a format that webpack can combine into an output bundle.js.

And here's an example usage for unit testing via a related plugin https://github.com/k88hudson/babel-plugin-jsm-to-commonjs/

https://github.com/mozilla/activity-stream/blob/23a4dca949ebeffd80b749672f08ee40ffa27f99/karma.mc.config.js#L151

kael commented 4 years ago

Thanks for the reply. I'm partially able to run the plugin.

  1. With a basic JSM module, it works although it doesn't generate an ES6 output:
# src/modules/test.jsm

function Stuff() {
  return 123;
}

this.Whatever = {};
this.Stuff = Stuff;
var EXPORTED_SYMBOLS = ["Stuff", "Whatever"];
# output src/lib/test.js

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Stuff = Stuff;
exports.Whatever = void 0;

function Stuff() {
  return 123;
}

var Whatever = {};
exports.Whatever = Whatever;

And I can get this to work:

'use strict';

import { Stuff } from '../lib/test';

console.log('Test Babel', Stuff());
  1. Testing with a second modules, I come across two issues:
# src/modules/foo.jsm

const {utils: Cu} = Components;
const {Stuff, Whatever} = Cu.import("resource://modules/test.jsm", {});

this.Baz = 123;
this.EXPORTED_SYMBOLS = ["Stuff", "Whatever", "Baz"];

Ouputs:

# src/lib/foo.js

"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Baz = void 0;

var _test = require("resource://modules/test.jsm");

var _Components = Components,
    Cu = _Components.utils;
var Baz = 123;
exports.Baz = Baz;

The require'd module is not loaded correctly and Components is undefined.

This is the config:

~Not sure I understand how it determines the content of `resource://' URI.~

~I'm using that in chrome.manifest (for Thunderbird 60) also (although not sure it's used by the plugin at all):~

resource modules modules/
resource lib     lib/
kael commented 4 years ago

I've been able to get the plugin to run, not exactly as expected though ; I wanted to get as many modules as JSM modules, but haven't found how to get the module paths to be correctly rewritten, so I'm using a single lib/index.js ouput file.

Anyway, here's a working example (using Babel & Mocha):

  1. JSM modules to ES module:
    • .babelrc (for babel-plugin-jsm-to-esmodules):
      {
      "presets": [
      ["@babel/preset-env", {
      "modules": "false",
      "targets": {
      "esmodules": "false",
      },
      }]
      ],
      "plugins": [
      "@babel/plugin-proposal-object-rest-spread",
      ["jsm-to-esmodules", {
      "basePath": " /^resource:\/\/modules\//",
      "replace":"true",
      "removeOtherImports": "false"
      }]
      ]
      }

      Note: The `"modules": "false"``option output ES6 modules.

    • src/module/bar.js
      
      const EXPORTED_SYMBOLS = ['Bar'];

class Bar { helloWorld() { return 'Hello World'; } }

  - src/module/foo.js
```js
const EXPORTED_SYMBOLS = ['Foo'];

const { Bar } = ChromeUtils.import("resource:///modules/bar.js");

class Foo extends Bar {}

} export class Foo extends Bar {}


2. Testing with Mocha:
  - tests/.babelrc
```json
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "modules": "commonjs",
        "targets":{
          "esmodules":false
        }
      }
    ]
  ],
  "plugins": [
    "@babel/plugin-proposal-object-rest-spread"
  ]
}

import { expect } from 'chai';

import { Foo, Bar } from '../lib/index';

describe('Foo Bar Tests', () => {

let foo, bar;
beforeEach(function() {
    foo = new Foo(), bar = new Bar();
 });

it("should match", function(done) {
    expect(foo.helloWorld()).to.eql(bar.helloWorld());
    done();
});

});

  - running test:

mocha -r esm --debug --require @babel/register --recursive tests/

_Note: [`esm`](http://npmjs.com/esm) is used [to load the modules](https://github.com/lodash/lodash/issues/3837#issuecomment-398410478)_.

  - package.json (devDependencies):
```json
  "devDependencies": {
    "@babel/core": "^7.6.4",
    "@babel/node": "^7.6.1",
    "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
    "@babel/preset-env": "^7.6.3",
    "@babel/register": "^7.6.2",
    "babel-plugin-jsm-to-commonjs": "^0.5.0",
    "babel-plugin-jsm-to-esmodules": "^0.6.0",
    "babel-preset-env": "^1.7.0",
    "chai": "^4.2.0",
    "esm": "^3.2.25",
    "mocha": "^6.2.2"
  }
kael commented 4 years ago

Regarding the ability to generate as many ES modules as JSM ones, I'm able to get this:

The problem is that the dot is missing from the path. Gotta look further on this.