Webpack ES6 modules circular dependencies when using index files - javascript

I have a big project, I try to refactor to ES6 modules right now.
To make further development easier, I wanted to introduce index files, which just export all modules within the directory:
index.js:
export { default as ModuleA } from './moduleA'
export { default as ModuleB } from './moduleB'
export { default as ModuleC } from './moduleC'
moduleA.js:
import { ModuleB } from './index'
moduleB.js:
import { ModuleC } from './index'
ModuleC.doSomething()
moduleC.js:
export default {
doSomething: () => {}
}
Starting point is ModuleA.
The problem is, that in ModuleB ModuleC is undefined, so doSomething can't be executed.
I suspect some issues with circular dependencies, since moduleB tries to access the index again, which parses moduleB before moduleC.
Is it just not possible to do this, or is there another solution?

The issue here is that ModuleC has not been exported by the time that ModuleB is exported and runs, and since ModuleC is a requirement of ModuleB, it can't run. If I were you, I would just export each of them from their own files, and when you import them, import them from their own files instead of index.js.
Example
ModuleA.js:
import { ModuleB } from 'moduleB.js'
export default {
// Your code here
}
ModuleB.js
import { ModuleC } from 'moduleC.js'
moduleC.doSomething();
ModuleC.js
export default {
doSomething: () => {
// Your code
}
}
And finally, since ModuleA is the entry point from index.js, just import it into index.js and run what you need to run.

Alright. Solved it.
The problem ist, that when ModuleB tries to import ModuleC from the index, the index will be parsed again and will see ModuleB before it can reach ModuleC.
It seems to work with only two modules, since the index file doesn't get reparsed, I think.
The solution:
Import modules, which try to load other modules from the index file at last.
So index.js should look like this:
export { default as ModuleA } from './moduleA'
export { default as ModuleC } from './moduleC'
export { default as ModuleB } from './moduleB'

Related

NextJS - Tree Shaking weird behaviour

I currently wanted to optimize handling modules on my application with the implemenation below described. I'm not sure why the page final bundle size increased. It only kept the same bundle size adding on the package.json the flag sideEffects: false
Does Nextjs treeshake modules out-of-the-box?
Module code
// file ModuleA.js
import React from 'react';
const ModuleA = props => (
// some code
);
export default ModuleA;
// file ModuleB.js
import React from 'react';
const ModuleB = props => (
// some code
);
export default ModuleB;
Page code
import ModuleA from '~/ModuleA';
import ModuleB from '~/ModuleB';
// Page size production build 25KB
Optimized module handling
// modules/index.js
export { default as ModuleA } from './ModuleA';
export { default as ModuleB } from './ModuleB';
export { default as ModuleC } from './ModuleC';
export { default as ModuleD } from './ModuleD';
Page code
import {
ModuleA,
ModuleB,
} from '~/modules';
// without sideEffects: false - production build 50KB
// with sideEffects: false - production build 25KB

In react why don't index.js files need to be specified on import? [duplicate]

I've noticed a few cases where I've seen something like the following:
// /reducers/reducer1.js
export default function reducer1(state = {}, action){
// etc...
}
// /reducers/reducer2.js
export default function reducer2(state = {}, action){
// etc...
}
// /reducers/index.js
import { combineReducers } from 'redux';
import reducer1 from './reducer1';
import reducer2 from './reducer2';
export default combineReducers({
reducer1,
reducer2
})
// /store.js
import masterReducer from './reducers';
export default function makeStore(){
// etc...
}
Notice the last "file" where we call import masterReducer from './reducers' - A few people seem to believe this should import the default export from the index.js file.
Is this actually part of the specification? - my interpretation/question is that this is the result of many folks using WebPack v1 which translates import statements into CommonJS-style requires statements? Or will this break in WebPack v2 with "official" import/export support?
Is this actually part of the specification?
No. How module identifiers ('./reducers' in your case) are resolved to the actual modules is left to the implementation of the module loader/bundler, it's not specificed by ES6. And it doesn't seem to be specified in CommonJs either.
This is just how node does it - when requiring a directory, it's index.js file will be used. Bundlers like browserify or webpack followed this convention (for compat reasons).

How import something from index.js in the same directory?

I have the similar folder structure as shown below
/components/organisms
-- ModuleA.vue
-- ModuleB.vue
-- index.js
content of index.js
export { default as ModuleA } from "./ModuleA.vue"
export { default as ModuleB } from "./ModuleB.vue"
If I try to import ModuleB into ModuleA, it generates an error
ModuleA.vue content
<script>
import { ModuleZ } from '#/components/molecules' // component from another directory, it works perfectly
import { ModuleB } from '#/components/organisms' // can't find, error
</script>
You cannot have an cyclic dependency structure with imports.
ModuleA requires index
index requires ModuleA
This generates undefined behaviour when bundled with webpack, usually manifesting as 1 of the files becoming undefined

destructuring from module imports

I have a index.js in a folder called "vuex" with the following
const module = { state, mutations, actions, getters }
export default { module, plugin }
state, mutations, actions were imported from another file
I'm trying to get the "state" property in another file so I
import module from './veux'
then
const { state } = module
however state is undefined which is weird because console.log(module) shows me that module.state is present
I'm new to this ES6-7 flow so but what exactly am I doing wrong here?
Since you have exported the object {module, plugin} as default export
after importing like
import module from './veux'
module will have structure like
module = {
module: { state, mutations, actions, getters },
plugin
}
so in order to access state, you will write module.module.state or
const {module: {state}} = module; // nested destructuring
console.log(state)
an easier to understand and readable method would be to export your module with named export like
export const module = { state, mutations, actions, getters }
export default plugin
and import it like
import plugin, { module } from './veux'
after which you can do
const { state } = module;
I'm trying to get the "state" property in another file so I
import module from './veux'
const { state } = module
however state is undefined which is weird because console.log(module)
shows me that module.state is present
No, you're importing the whole default-exported object (with its module and plugin properties) as module. The property would be module.module.state.
I have a index.js in a folder called "vuex" with the following
const module = { state, mutations, actions, getters }
export default { module, plugin }
Don't. Use named exports for exporting multiple things:
export const module = { state, mutations, actions, getters }
export { plugin }
then you can do
import { module } from './veux'
const { state } = module
It'll work if you do this:
import { module } from './veux';

what is the difference between import Task and import { Task } in es6

What is the difference between
import { Tasks } from '../api/tasks.js';
and
import Task from './Task.jsx';
when to use {} and when to not use {} ?
(by the way, this is from meteor tutorial https://www.meteor.com/tutorials/react/update-and-remove)
You don't have to use the {} when you precise that it's a default export.
For example :
export default class Test{}
You can do :
import Test from './test'
In the other hand, if you don't precise "default" keyword, you have to precise {} :
export class Test {}
gives
import { Test } from './test'
when you do
import { Tasks } from '../api/tasks.js';
you are importing Task module from '../api/tasks.js';
when you do
import Tasks from '../api/tasks.js';
you are importing default export module from '../api/tasks.js'; Here Task is a variable which is referring default export module.
Example.
task.js
export default Task;
case 1: It is Task from task.js
case 2: It is Task variable pointing to Task module in task.js that is Task
if I do
import someVariable from './api/task.js' still it will work because someVarible will point to default export module that is Task module in task.js
If I do
import {someVariable} from './api/task.js' it will search for module someVariable in task.js but it is not there so now it is undefined.
if you want to grab the all modules you can do
import * as test from "Test";
If you exporting only some modules and not all then you have to specify wictch module you want
import { Module1, Module2, Module3 } from "Modules"; //grab only given in {}
if you have only export default Test you can to
import "Test";
read more about modules

Categories