Use index.js to import multiple image assets in React - node.js

I have been using a pattern of collecting component files for export with index.js files placed in directories, for example:
// index.js file in /components directory
export { Splash } from './Splash'
export { Portfolio } from './Porfolio'
export { Contact } from './Contact'
In Layout.js (located in root directory) I can neatly import with one call:
import { Splash, Portfolio, Contact } from '.'
I use this pattern a lot as I structure components across directories and sub-directories.
My specific question is to ask if there is any way to extend this pattern to image assets collected in src/assets/img? Can I place an index.js file in my images directory and to be able to call groups of images to a component?
//index.js in /src/assets/img directory
export { Img01 } from './img-01.png'
export { Img02 } from './img-02.jpg'
export { Img03 } from './img-03.svg'
//Call in Component.js
import { Img01, Img02, Img03 } from '../assets/img'
I think this should be achievable, but I can't figure out the correct syntax or modifications required to this pattern. Any code samples or recommendations for better practices are appreciated. Thanks in advance!

To export default components do it like this:
export { default as Splash } from './Splash'
export { default as Portfolio } from './Porfolio'
export { default as Contact } from './Contact'
// you dont need to include the 'index' on the route, just do './' if you
// are in the same directory, but your export file must be named index.js
import { Splash, Portfolio, Contact } from './';
To export files: images, css, .svg etc, just include the file extension:
export { default as Img01 } from './img-01.png'
export { default as Img02 } from './img-02.jpg'
export { default as Img03 } from './img-03.svg'
//Call in Component.js
import { Img01, Img02, Img03 } from '../assets/img'

if you are using webpack take a look at this require. You can use require to import a file like the example below:
tree directory
-images
|_index.js
|_notification.png
|_logo.png
-pages
|-home.js
images/index.js
export const notification = require('./notification.png')
export const logo = require('./logo.png')
pages/home.js
import { notification } from '../images/'
<img src={notification} />
i hope i helped you

Related

Next Js take several params in the root

Suppose, I want to take params region and lang in URLs like:
https://root.com/{region}/{lang}
https://root.com/{region}/{lang}/school
How do I do that? I tried Dynamic Routing, but it doesn't seem to work with the root index.js. How should I structure my folder tree?
/pages/[region]/[lang]/index.js Doesn't look like a valid one.
In your default exported component in /pages/[region]/[lang]/index.js you can use next/router - useRouter.
The query object will contain the region and lang parameters.
import { useRouter } from "next/router";
export const Page = () => {
const { query } = useRouter();
console.log({ query });
return <>My index page!</>;
};
export default Page;
to get the /school path simply add a school.js file in the same folder as index.js and get query params with useRouter as above.
Hey I believe there are couple ways,
Use dynamic routing for URLs like https://root.com/{region}/{lang}.
Create a "pages" folder with subfolders for each region and language. Inside each subfolder, have an "index.js" file.
Use a library like "next-routes" or "react-router" for routing.

Splitting inversifyJS config file into multiple files

I recently bumped into a backend project using Typescript and would like to implement IoC principle with the help of Inversify.js. Following the official documentation, I have one huge file named inversify.config.ts containing all my interfaces and classes that implement them:
import "reflect-metadata"
import { Container } from "inversify"
import TYPES from './types';
import { ModuleRepo } from '../repo/interfaces'
import { ModuleARepoImpl } from '../repo/moduleA'
import { ModuleBRepoImpl } from '../repo/moduleB'
import { ModuleService } from '../services/interfaces'
import { ModuleAServiceImpl } from '../services/moduleA'
import { ModuleBServiceImpl } from '../services/moduleB'
const container = Container();
container.bind<ModuleRepo>(TYPES.ModuleARepo).to(ModuleARepoImpl);
container.bind<ModuleRepo>(TYPES.ModuleBRepo).to(ModuleBRepoImpl);
container.bind<ModuleService>(TYPES.ModuleAService).to(ModuleAServiceImpl);
container.bind<ModuleService>(TYPES.ModuleBService).to(ModuleBServiceImpl);
export default container;
One big problem in the above setting is when the project gets complex, more modules are added resulting in a very long config file (imagine you have dozens of modules). My plan is to divide it into smaller config files, with inversify.config.ts remains the main file.
consider the following settings:
./dependencies/interface/index.ts
import { Container } from 'inversify';
export type InversifyContainer = Container
export interface BasicInterface {
register(container: InversifyContainer): void
readonly types: Object
}
./dependencies/moduleA/index.ts
import {InversifyContainer, BasicDependencies} from '../interface';
import { ModuleRepo } from '../../repo/interfaces'
import { ModuleARepoImpl } from '../../repo/moduleA'
import { ModuleService } from '../../services/interfaces'
import { ModuleAServiceImpl } from '../../services/moduleA'
export class ModuleADependencies {
register(container: InversifyContainer) {
container.bind<ModuleRepo>(TYPES.ModuleARepo).to(ModuleARepoImpl);
container.bind<ModuleService>(TYPES.ModuleAService).to(ModuleAServiceImpl);
}
readonly types = {
ModuleARepo: Symbol('ModuleARepo'),
ModuleAService: Symbol('ModuleAService'),
}
}
./dependencies/inversify.config.ts
import "reflect-metadata"
import { Container } from "inversify"
import { ModuleADependencies } from './moduleA';
import { ModuleBDependencies } from './moduleB'; // consider moduleB also has the same file
const container = Container();
const registrationList = [ModuleADependencies, ModuleBDependencies];
for (const reg of registrationList) {
new reg().register(container);
}
export default container;
./dependencies/types.ts
import { ModuleADependencies } from './moduleA';
import { ModuleBDependencies } from './moduleB';
const TYPES = {
...(new ModuleADependencies().types),
...(new ModuleBDependencies().types),
}
export default TYPES
However, this way I always have an error showing something like Cannot read property of ModuleARepo of undefined from the types. I browsed the internet however nobody seems to care about how lengthy and messy inversify.config.ts would be if it is in a complex project.
Hoping someone can help with this :)
First of all your problem is described in the doc and has a solution.
Your solution is generally correct but there is a circular dependency
./dependencies/types.ts -> ./dependencies/moduleA/index.ts -> ./dependencies/types.ts
In types a new instance of class is created but the module that contain the class definition imports types. You don't list this import but use TYPES.ModuleARepo in bind.
To avoid it you can make types field static or move it out of the class into a separate exportable object. As a positive side effect of it, there will be no need to instantiate a class in ./dependencies/types.ts.
Just in case please keep in mind that if you instantiate a class that has a Symbol as a field this symbol is unique for every instance since Symbol('ModuleARepo') !== Symbol('ModuleARepo').
Playground

NodeJS - Cannot find custom module in Linux. Works fine in windows

The below is my folder struture
--package.json
--node_modules
--dist
--server.js
----app
------driver
------utils
Inside 'driver' folder I have driver.model.ts file which references BaseValidator
import { BaseValidator } from '../utils/BaseValidator';
export class LoginDriverModel extends BaseValidator {
...
}
Inside the 'utils' folder I have a file called BaseValidator.ts like
export class BaseValidator {
}
Now when I run below commands in windows and linux after setting environment variable NODE_ENV=dev
node server.js [works fine in windows]
nodejs server.js [uncaughtException: Cannot find module '../utils/BaseValidator' in Linux]
The issue seems to happen in Linux if we have the same file name and class name, in the same case. The issue got resolved after changing the file name from 'BaseValidator.ts' to 'baseValidator.ts'.
Referencing the class is like below,
import { BaseValidator } from '../utils/baseValidator';
export class LoginDriverModel extends BaseValidator {
...
}

Create a custom typings file

I just created a published npm package for the first time, called "Foo". I am trying to consume it in a typescript project, but none of the tutorials about how to declare modules with custom typings, are clear to me. Here are the key parts of the npm package:
news.ts
import { tdsRequest } from "../common/request";
function articles(uri) {
return tdsRequest({ method: "GET" }, uri).then(returnData => console.log(returnData, "return data"));
}
export {
articles,
};
main.ts (main export)
import * as news from "./services/news";
export default {
news
};
in the typescript project that's consuming the npm package:
import { news } from "Foo";
and in the typings file ( Foo.d.ts ) I did:
declare module "Foo" {
export {
news: Object,
};
}
I get the following errors: cannot find module news and Cannot export 'Object'. Only local declarations can be exported from a module.
You are mixing default and named exports.
You can do default export style -
main.ts:
import * as news from "./services/news";
export default {
news
};
ts project import:
import foo from "Foo";
const {news} = foo;
foo.d.ts:
declare module "Foo" {
export default {
news: Object,
};
}
Or you can do named exports:
main.ts:
import * as news from "./services/news";
export {
news
};
ts project import:
import {news} from "Foo";
foo.d.ts:
declare module "Foo" {
export const news: Object;
}
But more importantly, you should add declaration: true to your compilerOptions in tsconfig.json in your npm library.
This will generate the d.ts file for you and will save you lots of work. Then, you need to add in package.json a filed called types that will point to the main.d.ts file that will be generated for you. This will allow any project using your library + typescript to use the generated types automatically.

Angular2 + TypeScript + moment.js => locale are not all there (just 'en')

I am going thru a book tutorial to learn TypeScript and AngularJS 2.0:(Become_a_Ninja_with_Angular2).
At some point it explains how to make your own Pipe and goes thru an implementation of moment.js.
In the folder where my project is located I do in CLI: npm install moment
(FYI: The book also tells to do typings install --save --ambient moment-node, but that throws an error even if I change --ambient by --global, also this error happens to not be a problem to use moment.js as the rest of the code I describe below runs).
Then, as a result of previous CLI, it creates under my project folder: [my project folder]\node_modules\moment
Then in [my project folder]\main.html, I have a <script> tag with: `
<script>
System.config({
defaultJSExtensions: true,
map: {
... [plenty of stuff starting with #angular]..
'#angular/platform-browser-dynamic':'node_modules/#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'rxjs': 'node_modules/rxjs',
'moment':'node_modules/moment/moment'
}
});
System.import('main');
</script>
My custom Pipe looks like this:
import { PipeTransform, Pipe } from '#angular/core';
import * as moment from 'moment';
import 'moment/../locale/fr';
#Pipe({name: 'fromNow'})
export class FromNowPipe implements PipeTransform {
transform(value,args){
let mydate = moment(new Date(value));
console.log(moment.locales());
return mydate.fromNow();
}
}
As you can see in my custom pipe code, to access the locale 'fr', I had to add import 'moment/../locale/fr (what I found by looking at already existing solution on StackOverflow). If this tag was not implemented I had access to 'en' only. Which means that adding other languages will require to add import 'moment/../locale/[the locale I want available].
Anyone has any ideas how to have all the locale from the lib moment.js with just the single import * as moment from 'moment'; statement?
PS: And I added to [My project folder]\app.module.ts:
import { FromNowPipe } from './custom_pipes/fromnow.pipe';
...
#NgModule({
...
declarations: [...,FromNowPipe],
...
})
...
And somewhere in one of my component I have:
[#Component({
selector: 'ns-mycomponent',
template:`
.. <div>{{ '2016/05/01'|fromNow }}</div>..
`
})
I found a workaround:
Based on what I wrote in the question, in [my project folder]\main.html:
System.config({
defaultJSExtensions: true,
map: {
...
}
});
I substitued: 'moment':'node_modules/moment/moment' with 'moment':'node_modules/moment/min/moment-with-locales.min.js'
In my Pipe file I just kept: import * as moment from 'moment';at the beginning of the file and it works: all languages are available.

Resources