native-url
native-url copied to clipboard
Named exports as default export
native-url
exposes methods thorugh named exports. To get default Node url
behavior you would need to import entire module contents
import * as url from 'native-url'; // or 'url' if aliased`
This is fine for your own code, but dependencies will throw error since they can’t find default export by default, and most 3rd party code using Node url
depend on that default export to be available.
To fix this, it’s best to make changes to code at compile time to expose every named export as property of object which should be default export.
Here is a Babel plugin code which achieves that:
const babel = require('@babel/core');
const plugin = babel.createConfigItem(({ types: t }) => {
return {
visitor: {
ExportNamedDeclaration(path, parent) {
const properties = path.node.specifiers.map((node) => ({
exported: node.exported.name,
local: node.local.name
}));
path.insertAfter(
t.exportDefaultDeclaration(
t.objectExpression(
properties.map((prop) =>
t.objectProperty(
t.identifier(prop.exported),
t.identifier(prop.local)
)
)
)
)
);
}
}
};
});
And here is how you apply it with Webpack:
{
test: /\.m?js$/,
include: /node_modules\/native-url/,
use: [
{
loader: 'babel-loader',
options: {
plugins: [plugin]
}
}
]
};
After that you can use both modules’ named exports as default export.
Is this something which should be documented for both Webpack and Rollup, or should native-url
expose default export by default?
The exports are the same as the default node-url
library which webpack uses when bundling for client
I'm assuming everyone developed their libraries based on node-url
's export interface (which is the same as url
) coupled with babel and Webpack/rollup to handle the resolution? If thats the case this won't be an issue.
I'm curious to know cases when people have used the default import, since both url
and node-url
don't support it?
Please let me know
@janicklas-ralph
This doesn’t throw warning:
const url = require('url');
This does throw warning:
import url from `url`;
Hash: 30643d8377069131206c
Version: webpack 4.43.0
Time: 113ms
Built at: 2020-05-20 11:16:05
Asset Size Chunks Chunk Names
out.js 14.4 KiB 0 [emitted] main
Entrypoint main = out.js
[./index.js] 125 bytes {0} [built]
+ 5 hidden modules
WARNING in ./index.js 4:0-3
"export 'default' (imported as 'url') was not found in 'url'
WARNING in ./node_modules/dependancy/index.js 3:0-3
"export 'default' (imported as 'url') was not found in 'url'
@ ./index.js
Documentation is misleading in saying this:
With this in place,
import url from 'url'
will usenative-url
and keep your bundle small.
This happens because the module is being imported as ESM. node-url
is only published as CJS, so it always triggers emulated exports.default
in Webpack.
@janicklas-ralph - It might be worth removing the module
entry to make it exactly the same as node-url
? This would cause import * as
and import
to work identically.
@developit maybe export object (with all named exports as properties of that object) as default export and rely on tree-shaking from bundlers for any unwanted exports?