I have a parent directory that contains children directories, where each contains an SVG component and I only need to import some of them. I'm currently importing all the components I need by doing this:
import FacebookIcon from 'project/icons/Facebook';
import TwitterIcon from 'project/icons/Twitter';
import DiscordIcon from 'project/icons/Discord';
import MediumIcon from 'project/icons/Medium';
import YoutubeIcon from 'project/icons/Youtube';
However this seems very verbose. Is there a less verbose way of doing this?
I thought about destructuring, but I wasn't sure how to do this since each file is in a different folder.
Typically, you want to import similar components from a single source (you will get auto-complete too):
import {
FacebookIcon,
TwitterIcon,
DiscordIcon,
DiscordIcon,
MediumIcon,
YoutubeIcon,
} from "project/icons";
// Usage
<FacebookIcon/>
// Same
import Icons from './project/icons';
// Usage
const Icon = Icons.FacebookIcon;
<Icon/>
To achieve this, create index.js file in project/icons and make named export for each of the components.
export { default as FacebookIcon } from "./FacebookIcon";
...
Related
For example, the recommended way of importing in React Bootstrap is to go this way:
import Button from 'react-bootstrap/Button' instead of import { Button } from 'react-bootstrap';
The reason is "Doing so pulls in only the specific components that you use, which can significantly reduce the amount of code you end up sending to the client."
source: https://react-bootstrap.github.io/getting-started/introduction/
Same for React MUI components:
import Button from '#mui/material/Button';
source: https://mui.com/material-ui/getting-started/usage/
I want to implement something similar in my React components library, to limit the usage of code in the bundle, but I don't know how they implement this specific pattern. I have looked at their code base, but I don't quite understand.
Basically it is all about modules and module files and their organization. You can have a lot of.. lets call them folders, "compoments/*" for example. "components/button", "components/alert", "component/badge", and other things. All of them will have some index.js or .ts file that will export or declare and export all the functionality that needed in order to make this component work, 'react-bootstrap/Button' for example. Ideally all those subfolders or submodules are independend from each other, no references between them but probably each one will have 1 reference to 1 common/shared submodule like "components/common" which will contain some constants, for example, and no references to other files. At the top level of them you will have another index.js or .ts file that is referencing all of those components, so "components/index.js" will import and reexport all the nested components index files. So in order to import a Button, for example, you can either import "components/index.js" file with all the other imports this file is using, either only 1 single "components/button/index.js" file which is obviously much more easy to fetch. Just imagine a tree data structure, you import root of the tree (root index.js) - you get all the tree nodes. You import one specific Node (components/button/index.js) of the tree - just load all the childs (imports) of that node.
Sorry for a long read but asuming you mentioned webpack - there is a technique called tree-shaking which will cut off all the unused things.
Info about modules: https://www.w3schools.com/js/js_modules.asp
Info about Tree-Shaking: https://webpack.js.org/guides/tree-shaking/
It might not be as complicated as you think. Let's say you write the following library:
// your-library.js
const A = 22
const B = 33
export function getA () { return A }
export function getB () { return B }
export function APlusB () { return A + B }
// a lot of other stuff here
If some consumer of your library wants to make use of the APlusB function, they must do the following:
// their-website.js
import { APlusB } from 'your-library'
const C = APlusB()
However, depending on how the code is bundled, they may or may not wind up with the entire your-library file in their web bundle. Modern bundling tools like Webpack may provide tree shaking to eliminate dead code, but this should be considered an additional optimization that the API consumer can opt into rather than a core behavior of the import spec.
To make your library more flexible, you can split up independent functions or chunks of functionality into their own files while still providing a full bundle for users who prefer that option. For example:
// your-library/constants.js
export const A = 22
export const B = 33
// your-library/aplusb.js
import { A, B } from 'constants'
export default function APlusB () { return A + B }
// your-library/index.js
// instead of declaring everything in one file, export it from each module
export * from 'constants'
export { default as APlusB } from 'aplusb'
// more exports here
For distribution purposes you can package your library like so:
your-library
|__aplusb.js
|__constants.js
|__index.js
You mentioned react-bootstrap and you can see this exact pattern in their file structure:
https://github.com/react-bootstrap/react-bootstrap/tree/master/src
and you can see they aggregate and re-export modules in their index file here:
https://github.com/react-bootstrap/react-bootstrap/blob/master/src/index.tsx
Essentially, what you are asking is:
"How to export react components"
OR
"How are react components exported to be able to use it in a different react project ?"
Now coming to your actual question:
import Button from 'react-bootstrap/Button' instead of import { Button } from 'react-bootstrap';
The reason is 'Button' component is the default export of that file react-bootstrap/Button.tsx. So there is no need for destructuring a specific component.
If you export multiple components/ functions out of a file, only 1 of them can be a default export.
If you have only 1 export in a file you can make it the default export.
Consider the file project/elements.js
export default function Button(){
// Implementation of custom button component
}
export function Link(){
// Implementation of custom Link component
}
function Image(){
// Implementation of custom Image component
}
Notice that the Button component has 'default' as a keyword and the Link component doesn't.
The Image component can't even be imported and can only be used by other functions/components in the same file.
Now in project/index.js
import 'Button', {Link} from './elements.js'
As Button component is the default export its possible to import without destructuring and as Link component is a regular export, I have to destructure it for importing.
Currently, I have a folder in a Vue project which contains all my default images that it has been used through the app. The folder path is web/images/defaults/<imageNames>.png. I'm able import the images on my component by importing them individually like so:
import ImageName from '../../../../../../web/images/defaults/ImageName.png'
However, I want to create a file & add the images path to const variables & being able to import the file in the component.
I have tried:
import imageName1 from 'imageName1.png';
import imageName2 from 'imageName2.png';
const DEFAULT_IMAGES = {
imageName1:'imageName1',
imageName2:'imageName2',
};
export default DEFAULT_IMAGES;
Then, I imported it in my component like so:
import DEFAULT_IMAGES from '../../assets/images';
And I tried to v-bind to the src attribute
<img :src="DEFAULT_IMAGES.imageName1" >
However, it's not working as soon as I imported. What am I doing wrong?
I have found the solution:
I didn't include the right path to get the images. Originally, I tried to access the images in the same folder like so:
import imageName1 from 'imageName1.png';
import imageName2 from 'imageName2.png';
const DEFAULT_IMAGES = {
imageName1:'imageName1',
imageName2:'imageName2',
};
export default DEFAULT_IMAGES;
However, I needed to add ./ before the image name like so:
import imageName1 from './imageName1.png';
import imageName2 from './imageName2.png';
const DEFAULT_IMAGES = {
imageName1:'imageName1',
imageName2:'imageName2',
};
export default DEFAULT_IMAGES;
I am very new to Vue and I have read an article or two about it (probably vaguely).
Also, Since I have some understanding of react, I tend to assume certain things to work the same way (but probably they do not)
Anyway, I just started with Quasar and was going through the Quasar boilerplate code
In the myLayout.vue file, I see being used inside my template
<template>
<q-layout view="lHh Lpr lFf">
<q-layout-header>
<q-toolbar
color="negative"
>
<q-btn
flat
dense
round
#click="leftDrawerOpen = !leftDrawerOpen"
aria-label="Menu"
>
<q-icon name="menu" />
</q-btn>
based on my vaguely understanding, I thought for every component we are using to whom we need to pass props we need to import it as well but unfortunately I can't see it in my import-script area
<script>
import { openURL } from 'quasar'
export default {
name: 'MyLayout',
data () {
return {
leftDrawerOpen: this.$q.platform.is.desktop
}
},
methods: {
openURL
}
}
</script>
I would've thought the script to be something like
<script>
import { openURL } from 'quasar'
import {q-icon} from "quasar"
or at least something like that but here we only have
import { openURL } from 'quasar'
Also, Even if we remove the above snippet, our boilerplate app looks to be working fine so here are my two questions
Question 1: What is the use of import { openURL } from 'quasar' (like what it does)
Question 2: How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
How can template contain <quasar-icon> or <quasar-whatever> without even importing it in script tag?
There are two ways to import components. The first way (which I recommend, and being most similar to React) is to import the component and add it to the components option inside the component that you want to use it within.
App.vue
<div>
<my-component/>
</div>
import MyComponent from 'my-component'
export default {
components: {
MyComponent
}
}
The second way is to import it globally for use within any Vue component in your app. You need only do this once in the entry script of your app. This is what Quasar is doing.
main.js
import Vue from 'vue'
import MyComponent from 'my-component'
Vue.component('my-component', MyComponent)
What is the use of import { openURL } from 'quasar' (like what it does)
I'm not familiar with Quasar, so I can't give you a specific answer here (I don't know what openURL does). You should check the Quasar docs.
openURL is being used as a method here. Perhaps it is being called from somewhere in the template (which you have excluded from the question).
A1) Import statement is 1 way (es6) way to split your code into different files and then import functions/objects/vars from other files or npm modules see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
A2) Vue allows 2 mechanisms to register components. Global and local. Globally registered components does not have to be imported and registered in every component before use (in template or render fn). See URL from comment above https://v2.vuejs.org/v2/guide/components-registration.html#Global-Registration
I´ve several React components as a library in folder ux (some itens below):
import MessageBar from "./atoms/MessageBar/MessageBar";
import Spinner from "./atoms/Spinner/Spinner";
import Button from "./atoms/Button/Button";
import AccordionHeader from "./molecules/AccordionHeader/AccordionHeader";
import AutocompleteList from "./molecules/AutocompleteList/AutocompleteList";
import ButtonGroup from "./molecules/ButtonGroup/ButtonGroup";
import LoginPanel from "./organisms/LoginPanel/LoginPanel";
import WelcomePanel from "./organisms/WelcomePanel/WelcomePanel";
I wish to export these objects so that it can be imported from its group:
import LoginPanel from "ux.organisms";
Or
import Button from "ux/atoms";
Or whatever.
The idea is that you are getting the element from an specific group inside ux library.
What is the suggested way to export all of those components, organized into groups (atoms, molecules, organisms, etc.) ?
PS:
a. I don´t wnat to change the component name (ButtomAtom, etc...)
b. The result will be a npm library to be imported by other projects. So, this code will reside on my ux/index.js file.
Then make a index.js file at ux/atoms/ and fill it with:
import MessageBar from "./MessageBar/MessageBar";
import Spinner from "./Spinner/Spinner";
import Button from "./Button/Button";
//...
export { MessageBar, Spinner, Button };
So now one can do:
import { MessageBar } from "ux/atoms";
Or if you need every submodule:
import * as Atoms from "ux/atoms";
Currently a typical component will look like the below code. Note that using the paths to the file has become problematic and ugly. Moving a file causes massive issues with updating paths across multiple components.
This truly takes away from the component based experience when a path change can break everything and cause mass find and replace of paths.
In an ideal world the displayName would be the import reference and searched for within the directory.
'use strict';
//libs
import React from 'react';
//components
import TopFeatures from '../../headphones/subcomponents/top-features';
import Prices from './prices';
import Image from '../../layout/image';
import InlineRatingElement from '../../reviews/rating';
//helpers
import { getImageUrl } from '../../helpers/app/image';
import { initiateInlineRatings } from '../../helpers/app/inline-ratings';
export default class HDOverview extends React.Component {
displayName = 'HDOverview'
static propTypes = {
vendor: React.PropTypes.string.isRequired
}
constructor(props) {
super(props);
}
render() {
return (
<div>
JSX
</div>
);
}
}
I am looking to do something like this:
import TopFeatures from 'TopFeatures';//TopFeatures is the displayName
import Prices from 'Prices'; //Prices is the displayName etc.
import Image from 'Image';
import InlineRatingElement from 'InlineRatingElement';
//helpers
import { getImageUrl } from 'ImageHelper';
import { initiateInlineRatings } from 'InlineRatingHelper';
Webpack has a great tutorial on resolve aliases here: http://xabikos.com/javascript%20module%20bundler/javascript%20dependencies%20management/2015/10/03/webpack-aliases-and-relative-paths.html
However this insinuates that the path to the component would need to be logged in one place - in an ideal world there would be a way to dynamically check paths / directories to find the displayName that matches. Note that we have 200 components, so manually creating that list is do-able but sizable.
Having looked around I have seen people using
require("components!/layout/image")
however we would like to stick to the import technique and not go back to require.
Any suggestions or advice are greatly appreciated.
I think that this is, unfortunately, a limitation of node, npm.
There are workarounds to get absolute/mapped paths to work in npm but all of these have drawbacks: https://gist.github.com/branneman/8048520
Another option is individual npm packages for each component, but this adds a lot of overhead.