2

I'm working on a project with nuxt.js and I want to implement the atomic design methodology

so I currently import the components like this

import ButtonStyled from '@/components/atoms/ButtonStyled.vue'
import TextLead from '@/components/atoms/TextLead.vue'
import InputSearch from '@/components/atoms/InputSearch.vue'

but I need to import like this

import {
    ButtonStyled,
    TextLead,
    InputSearch
} from '@/components/atoms'

the closer I got was that,

/atoms/index.js
const req = require.context('./', true, /\.vue$/)

const modules = {}

req.keys().forEach(fileName => {
  const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, '$1')
  modules[componentName] = req(fileName).default
})

export const { ButtonStyled, TextLead } = modules

but I'm still defining the export variable names statically, I need to define dynamics based on the components inside the folder

NOTE: I can not use

export default modules

if I use the above code snippet I will not be able to import the way I need it, which is:

import { ButtonStyled } from "@/components/atoms"
Yung Silva
  • 1,324
  • 4
  • 20
  • 40

3 Answers3

0

require.context is a quite obscure function in Webpack, you will have issues while running unit tests. But, to solve your problem; You will need to import the index.js file in the main.js of your project.

This is how I do it:

_globals.js

// Globally register all base components prefixed with _base for convenience, because they
// will be used very frequently. Components are registered using the
// PascalCased version of their file name.
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context('.', true, /_base-[\w-]+\.vue$/)

requireComponent.keys().forEach(fileName => {
  const componentConfig = requireComponent(fileName)

  const componentName = upperFirst(
    camelCase(fileName.replace(/^\.\/_base/, '').replace(/\.\w+$/, ''))
  )

  Vue.component(componentName, componentConfig.default || componentConfig)
})

components/index.js

//...
import './_globals'
//...

main.js

//...
import './components' // This imports in the index.js
//...

This way your components loaded in with require.context() gets registered as a vue component and made globally available. I advice to only use global components with components that will be used a lot. Do not load a component globally if you intend to use it only one time.

You can find a working example here -> https://github.com/IlyasDeckers/vuetiful/tree/master/src

To get your unit tests working with jest, you will need to mock require.context(). This was a true pain, but can be achieved easily by using babel-plugin-transform-require-context

Odyssee
  • 2,393
  • 2
  • 19
  • 38
  • as mentioned in the description of the question, I am using nuxt.js, so I do not have the main.js file and I do not want to register components globally, this has nothing to do with my question. I need to export components in index.js dynamically, export is different from registering globally, sorry for my bad english – Yung Silva Apr 25 '19 at 14:34
  • I updated my question with as close as I got to the solution, take a look please and if I can help – Yung Silva Apr 25 '19 at 18:48
0

I try to use your way to do that, and known you have make a mistake at module.exports
module.exports can not use import , i think you may can do like this
at atoms/index.js

const req = require.context("./", true, /\.vue$/);
const atoms = {};
req.keys().forEach(fileName => {
  const componentName = fileName.replace(/^.+\/([^/]+)\.vue/, "$1");
  atoms[componentName] = req(fileName).default;
});
export default atoms;

at where to use

import k from "@/components/atoms/index.js";
export default {
  components: {
    test1: k.test1,
    test2: k.test2
  }
};

or index.js

import test1 from "./test1.vue";
import test2 from "./test2.vue";

export { test1, test2 };

and where to use like this

import {test1,test2} from "@/components/atoms/index.js";

export default {
  components: {
    test1,
    test2
  }
};
  • still gets very verbose, large, component object, I need a solution like in my question ``` components: { ButtonStyled: atoms.ButtonStyled, TextLead: atoms.TextLead, InputSearch: atoms.InputSearch } ``` – Yung Silva Apr 25 '19 at 15:19
  • or you kan use this in your index.js :: import test1 from "./test1.vue"; import test2 from "./test2.vue"; export { test1, test2 }; – 纷羽shine Apr 25 '19 at 16:01
  • and I have put the new code at the answer, I have no way to auto export all file under the dir – 纷羽shine Apr 25 '19 at 16:05
  • so it is not dynamic export, it is static, fixed – Yung Silva Apr 25 '19 at 16:06
  • I know what you want ,but I think it is no way to do that, exports not require a dynamic name,and exports default only can import all of the object; I have see some util on NPM ,they are use the static way to do that. you may need see the article about [export](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export) on MDN – 纷羽shine Apr 25 '19 at 16:18
  • I updated my question with as close as I got to the solution, take a look please and if I can help – Yung Silva Apr 25 '19 at 18:48
  • I think it is not be allow to do like what you want – 纷羽shine Apr 26 '19 at 05:34
0

I created a library that does all this for me, maybe it helps other people.

named-exports

Community
  • 1
  • 1
Yung Silva
  • 1,324
  • 4
  • 20
  • 40