Publishing both es6 and commonjs with subfolders - javascript

I want to be able to import module from subfolder like this, without any lib folder, https://davidwells.io/blog/publishing-flat-npm-packages-for-easier-import-paths-smaller-consumer-bundle-sizes/
I want to publish both CommonJS and ES6 modules
I can specify the main file for commonjs with "main": "./index.js" and for es6 with "module": "./index.es.js" in package.json.
But how does it works when I import my-package/myfile ? Is myfile.js used or myfile.es.js
And why it isn't possible to specify a subfolder instead of a single main file ?

There's not a lot of magic going on in that blog post you mentioned, he's just asking for node_modules/his-module/P.js
The bundlers need a single entry because (in theory) that is where you have your
module.exports = {}
code which is what lets the bundlers access your functions.
If you are using an esmodule compatible bundler like webpack or rollup, they will read the module key
import someFunction from 'your-module';
Would import the es module unless you are using something like browserify which would take the commonjs version.
You can also ask explicitly for a different file
import someFunction from 'your-module/lib/index.min.js';
Whatever file you ask for here, it'll import that. If you add a / after your-module you are now breaking out of the main or module path conventions and asking for whatever file you want.

Related

Typescript module usage without ".js" ending

In typical JavaScript files we use require('some-module.js') to import functionality of this module where we need.
If we use TypeScript we also want to import this functionality using "import module from 'some-module.js'".
If we use nest.js we import using "import module from 'some-module'". The main thing that there is no ".js". How can i reach the same in for example express application. Maybe i should use webpack, babel or some special tsconfig.json configuration?
With Typescript's import and with Node's require, the extension is not necessary. Just the path to the file, or the name of the package you're importing. So in typescript you would do import * as module from 'some-module' and in js you would do const module = require('some-module'). You may want to check out this page on module resolution in Typescript.

How can I offer multiple module formats for subfiles of a published npm library

Given a package published on npm with a package.json that points to 3 separate distribution files, and that looks something like this:
{
...
"name": "#myorg/mymodule",
"main": "mymodule.umd.js",
"module": "mymodule.esm.js",
"unpkg": "mymodule.min.js"
}
and the public usage looks like:
import mymodule from '#myorg/mymodule'
mymodule() // ..does stuff
or when using commonJS
const mymodule = require('mymodule')
mymodule.default()
How do I structure my package to publish additional imports. For example, let’s say we want to publish a feature, or localization, and we don’t want that to be part of everyone's bundle, because only a few people will need that feature. Ideally the usage would look like:
import mymodule from '#myorg/mymodule'
import fr from '#myorg/mymodule/fr'
mymodule({
locale: fr
})
How can I structure my package to allow for this? Technically I'm able to do these imports, but if I publish an esm webpack or rollup fails (Unexpected token 'export') because they think it should be commonjs build and if I publish a umd they throw warnings about not being able to find the default export. The only effective way I was able to get this to work is when explicitly importing import fr from '#myorg/mymodule/fr.esm'
However, as a package maintainer, I would like to pre-configure the package to work better with the bundlers instead of requiring users to understand the internals of their bundler, or rely on their tree-shaking to reduce size. This already works great with main, module, and unpkg for the main file, how can I do something similar for other files?

How to choose 'module' instead of 'main' file in package.json

I have created some npm modules and compile them to:
commonJS (using exports.default =) and
esm (using export default)
I set up my package.json like so:
main: "index.cjs.js",
module: "index.esm.js"
When I npm install the package and I simple import it like:
import myPackage from 'my-package'
It will automatically choose the main file, not the module.
My question:
Is there a way to import the module file instead when doing import myPackage from 'my-package' in a JavaScript file?
Why I choose the commonJS file for "main":
I noticed that using Node, importing an esm file is not possible because of export default, it has to be commonJS. I have some simple helper JS functions like this and this, and I would want them to be usable to the widest audience. That's why I chose cjs for the "main" path in package.json.
Why I define a separate "module" in package.json:
Lots of famous libraries like Vue.js are already doing this. See further information on this Stackoverflow thread:
What is the "module" package.json field for?
Why do I want to be able to import the "module" file instead of the "main" file:
There is currently a bug in Rollup where it will not properly show JSDoc comments when coding after having imported a cjs file, but it does work when importing a es file.
The workaround I want to avoid:
Just set "main" to the esm file in package.json, right? But then all users who are using my packages in Node apps will not be able to use it anymore...
→ I'm really confused about all this as well, but I think I did enough research to make sense of all it. That being said, if anyone knows a better approach or any other advice, please do tell me in the comments down below!!
Just don't use extension for main file and have es6 and CommonJS version as two separate files with the same name and in the same directory, but with different extension, so:
index.js // transpiled CommonJS code for old nodejs
index.mjs // es6 module syntax
and in package.json:
{
"main": "index"
}
If node is launched with --experimental-modules flag, it would use *.mjs file, otherwise *.js.
Nodejs does not support "module" but does support the newer "exports" spec.
https://nodejs.org/api/packages.html#exports
https://github.com/nodejs/node/blob/v16.14.0/lib/internal/modules/esm/resolve.js#L910
"exports": {
"import": "./main-module.js",
"require": "./main-require.cjs"
},

Ember CLI import ES6 file to ember-cli-builds.js

So the ember-cli-builds.js file clearly states
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.
I'm importing regular javascript files this way
app.import('vendor/global.js');
but what is the proper way to "specify an object with the list of modules as keys along with the exports of each module as it's value"?
At the "AMD Javascript modules" heading of the guides, it is described like that:
Provide the asset path as the first argument, and the list of modules
and exports as the second.
app.import('bower_components/ic-ajax/dist/named-amd/main.js', {
exports: {
'ic-ajax': [
'default',
'defineFixture',
'lookupFixture',
'raw',
'request'
]
}
});
You can now import them in your app. (e.g. import { raw as icAjaxRaw } from 'ic-ajax';)
Reference From Guide
The selector answer is for older ember, pre ember-auto-import (webpack), and pre Ember Octane.
In modern ember, after npm installing a package, you'll be able to import directly from that package.
Example:
npm install qs
then anywhere in your app
import qs from 'qs';
related, it is recommended to avoid placing files in the vendor folder that you want to integrate with the module system. the vendor exists outside of the bundle, so if you have a standalone module, you can place it in your app folder, maybe under some descriptive folder:
app/external-modules/global.js, allowing you to import from it like:
import * as globalStuff from '<my-app>/external-modules/global';

EcmaScript 6 module requiring, how does it work?

So I know how to require and export modules in ES6. But for frameworks like Aurelia, the docs say that you require aurelia like so:
import {LogManager} from 'aurelia-framework';
Do I have to place a JS file named aurelia-framework in the folder where the JS file I'm executing it from resides, or does the import function work similiar to the require function in NodeJS/CommonJS?
According to this article ES6 modules spec only deals with loading modules that are present in the file path. Downloading these files (via NPM or by other means) is outside of scope of ECMAScript 6 modules spec. Nothing is said in the spec about supporting npm package includes (traversing the directory structure down to the /, one directory at a time, looking for a package.json file and then searching within the node_modules directory where package.json file is found). So while the import syntax is similar to commonJS style, the whole magic of looking for modules in the node_modules directory is not included.
So for your example to work, aurelia-framework must be a javascript file somewhere in your file system and it should contain an exports statement.
import {LogManager} from 'aurelia-framework'; // ./aurelia-framework.js
import {LogManager} from '../libs/aurelia-framework'; // ../libs/aurelia-framework.js
with Aurelia, you can install dependent libraries using jspm. you can see an example of that here. jspm will get the packages for you and bring them into subfolders in your project. jspm uses an index (stored in config.js) to know where to locate the files (similar to how requirejs, but works for amd, commonjs, and es6 modules).
there is also an example of using the aurelia libraries with requirejs amd loader. this example uses a bundle of aurelia libraries generated by r.js as shown here

Categories

Resources