Why is export default suddenly useless?

Time:2021-11-30

preface

A few days ago, my team friend asked me a question. I used deconstruction in the TS file to export a variable in other placesimportCame in and found it wasundefined, like this

//a.ts
export const a = {
   a1: 1,
   a2: 2
}

export const b = {
    b1: 1
}

export default {
 ...a,
 b
}
// b.ts
import { a1 } from 'a';
console.log(a1): // undefined

Here’s a question?

Clearly usedbabel-plugin-add-module-exportsCompatibleexport default, but you just can’t get it?

Next, let’s learn why step by step from export default – > Babel – > add module exports

What is the function of export default

export defaultThe command specifies the default output of the module. Obviously, a module can only have one default output, soexport defaultThe command can only be used once. In essence,export defaultIs to output a file calleddefaultThen the system allows you to give it any name.

Like this
derived function

//a.js
export default funcion() {
   //xxx
}
//b.js
import foo from 'a';

Export object

//c.js
const c = { c1:1, c2:2 }
const d = { d1:1, d2:2 }
export default {
    c,d
}
//d.js
import obj from 'c'
console.log(obj); // {c:{c1:1,c2:2},d:{d1:1,d2:2}}

Export default

//a.js
function foo(){}
export { foo as default};
//Equivalent to
// export default foo;

// b.js
import { default as foo } from 'a';
//Equivalent to
// import foo from 'a';

Everything looks good here. There is a new problem: whered.jsInside, I want to get it directlyobjInsidecProperty, OK?

const c = { c1:1, c2:2 }
const d = { d1:1, d2:2 }
export default {
    c,d
}
//d.mjs
import {c} from 'c'
console.log(c); //  Wrong report

// terminal
node --experimental-modules d.js
/*
import {c} from 'c';
        ^
SyntaxError: The requested module 'c' does not provide an export named 'c'
*/

In fact, this is wrong, because the import of ES6 is not object deconstruction syntax, but looks like it. You can refer to the description of import in MDNMDN import。 Therefore, import cannot deconstruct a default object.

Since import does not support the deconstruction of a default object, we have another question in mind. Why can we write export default freely in the project and get it through deconstruction?

Export default compilation result

export defaultbelong toES6In order to be compatible with browsers that do not support ES6, Babel compilation is required. Next, let’s look at the compilation of Babel,export defaultInto something.

Babel 5 Era

When using babel5, the following code

//a.js
const a = {};
const b = {};
export default {a,b}
//b.js
import {a} from 'b'
console.log(a)

Will be packaged as

//a.js
...
let _default = _objectSpread({}, {a, b});
exports.default = _default;
module.exports = exports.default;

//b.js
"use strict";
var _const = require("./a");
console.log(_const.a);

Babel parses the ESM into CJS. We execute B.js and find that the value can be obtained. However, in the browser environment, we also need webpack because webpack simply wraps the files converted by Babel with a layer of require. Therefore, we don’t talk about what webpack does here. We only discuss what Babel does. You can check it here

Interpretation of webpack startup code
Webpack modular principle

Babel 6 Era

After the project was upgraded to Babel 6, it was found that the previous writing method could not get the value. After the above A.js and B.js were packaged, they became

//a.js
...
let _default = _objectSpread({}, {a, b});
exports.default = _default;
//Babel6 removes module. Exports = exports. Default;

//b.js
"use strict";
var _const = require("./a");
console.log(_const.a);

This time_constThe value of is{default: {a:{},b{}}}
The reason for this is because of Babel’s issueKill CommonJS default export behaviourTherefore, Babel 6 is no longer executedmodule.exports = exports['default']Module transformation to change some behavior. Babel5 supports the export of an object, but this feature is removed when it comes to babel6. At this time, we need a solution to be compatible with old codebabel-plugin-add-module-exportsHere we go.

Babel plugin add module exports

babel-plugin-add-module-exportsThe main function is to complete babel6module.exports = exports.default;
Here’s the problem. The project is configuredbabel-plugin-add-module-exportsWhy is there a problem with the code at the forefront

Failure reason of Babel plugin add module exports

The answer is very simple. We find that Babel plugin add module exports is invalid. Go deep into the source code and make a log to find out whether there is name export. If there is name export, the feature of babel5 export default object will not be added.

//Hasexportnamed is always true
...
if (hasExportDefault &&  !hasExportNamed) {

path.pushContainer('body', \[types.expressionStatement(types.assignmentExpression('=', types.memberExpression(types.identifier('module'), types.identifier('exports')), types.memberExpression(types.identifier('exports'), types.stringLiteral('default'), true)))\]);

}
...

Solution:
We just need to change the code to

//a.ts
const a = {
   a1: 1,
   a2: 2
}
const b = {
    b1: 1
}
export default {
 ...a,
 b
}
// b.ts
import { a1 } from 'a';
console.log(a1): // 1

We only need to remove export const and keep export default to solve this problem.

Some curious students asked why they would not complete it with name exportmodule.exports = exports.default。 You can see the following example

//a.ts
export const a = {
   a1: 1,
   a2: 2
}
const b = {
    b1: 1
}
export default {
 b
}
// b.ts
import { a } from 'a';
console.log(a);

Add one manually after packingmodule.exports = exports.default

//a.js
...
let _default = _objectSpread({}, {b});
exports.default = _default;
module.exports = exports.default;

As a result, it is conceivable that when the B file requires to enter, a cannot find it

//b.js
"use strict";
var _const = require("./a");
console.log(_const.a); // undefined

epilogue

export defaultcoordinationbabel-plugin-add-module-exportsIt gives us a good development experience, but we still have to abide by itexport defaultBasic rules:
althoughes6 export defaultThere are tools to handle the exported content, butes6 importNot deconstructive grammar. It should be noted that when introducing a module with default outputimportAfter the command, do not use braces and do not deconstruct the introduced content.

Help link:

About import, require, export, module.exports