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
Related
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).
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
I'm making a Vue js application in which I need to export all the files / components from a certain directory and import those files / components them in a file i.e path.js.
How should I exports the components if I require them all in index.js so that I can access them in path.js as import {Component1,Component2} from index.js?
Note: I don't want to explicitly include components in index.js with import keyword that is why I used require.
Index.js
import upperFirst from "lodash/upperFirst";
import camelCase from "lodash/camelCase";
const requireComponent = require.context(".", true, /\.vue$/); // used to fetch Component1.vue and Component2.vue
const components = {};
requireComponent.keys().forEach(fileName => {
const componentConfig = requireComponent(fileName);
const componentName = upperFirst(
camelCase(fileName.replace(/^\.\//, "").replace(/\.\w+$/, ""))
);
components[componentName] = requireComponent(fileName).default;
});
export default components;
paths.js
import {Component1,Component2} from 'index.js';'
console.log(Component1); // undefined
I've tried exporting components as export {...components} but that throws an error.
It should be
import Component from 'index.js'
As you exported it in just a single constant value.
There is no such thing as Component1 or Component2 in Index.js, but I think I know what you are looking for.
You can achieve it through Named exports and imports.
Simple example below:
index.js
export {components[0] as Component1};
export {components[1] as Component2};
export default components;
paths.js
import {Component1, Component2} from 'index.js';
//some code
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'
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).