I want to know the best way to expose my server's API to my front-end web app. I know I could place all the code in just one file and it'd work. But I want to know a more organized way to expose it. So I came up with two ideias:
First: Export a module named API and this module export its sub modules like Authentication module, users, tasks... The problem with this aproach is that I couldn't find a way to make dotted imports like import { API.authenticate }, I need to import all things from api and then access the object.
import { authenticate } from "./src/authenticationService.module.js";
import { users } from "./src/usersSerivice.module.js";
import { tasks } from "./src/tasksSerivice.module.js";
import { projects } from "./src/projectsSerivice.module.js";
import { projectSteps } from "./src/projectStepsSerivice.module.js";
export const API = { authenticate, users, tasks, projects, projectSteps };
authentication.module.js;
import { API } from "../backend/api.module.js";
API.authenticate.login("email", "pass");
Second: A module for each endpoint like AuthenticationAPI, UsersAPI, TasksAPI... but the problem is that I think I'm creating to much repetitive module names.
An example:
export const authenticateAPI = { login };
authentication.module.js
import { authenticateAPI } from "../backend/authentication-api.module.js";
authenticateAPI.login("email", "pass");
Is any of these a good approach or you suggest a better one? I'm new to programming.
Related
So I am quite simply looking at how I can do a regular import e.g.
import { something } from 'myfantastic/package';
or even in a case:
import 'myfantastic/package/js/something.js';
I know I can do this within my <script> tag as a normal import but what I am trying to do is load a free package or pro package based on an env variable.
So I would like to be able do something like the following:
export default {
created() {
const something = ({something}) => import('myfantastic/package');
something.add( data )
}
}
If possible I would like to be able to do this for standard scripts e.g. 'myfantastic/package/js/something.js'; and CSS files e.g. 'myfantastic/package/css/style.css'.
How can I achieve this?
In the getServerSideProps function of my index page, I'd like to use a function foo, imported from another local file, which is dependent on a certain Node library.
Said library can't be run in the browser, as it depends on "server-only" modules such as fs or request.
I've been using the following pattern, but would like to optimize it. Defining foo as mutable in order to have it be in scope is clunky and seems avoidable.
let foo;
if (typeof window === "undefined") {
foo = require("../clients/foo");
}
export default function Index({data}) {
...
}
export async function getServerSideProps() {
return {
props: {data: await foo()},
}
}
What would be the best practice here? Is it somehow possible to leverage ES6's dynamic import function? What about dynamically importing within getServerSideProps?
I'm using Next.js version 9.3.6.
Thanks.
UPDATE:
It seems as if Next.js's own dynamic import solution is the answer to this. I'm still testing it and will update this post accordingly, when done. The docs seem quite confusing to me as they mentionn disabling imports for SSR, but not vice versa.
https://nextjs.org/docs/advanced-features/dynamic-import
When using getServerSideProps/getStaticProps, Next.js will automatically delete any code inside those functions, and imports used exclusively by them from the client bundle. There's no risk of running server code on the browser.
However, there are a couple of considerations to take in order to ensure the code elimination works as intended.
Don't use imports meant for the server-side inside client-side code (like React components).
Ensure you don't have unused imports in those files. Next.js won't be able to tell if an import is only meant for the server, and will include it in both the server and client bundles.
You can use the Next.js Code Elimination tool to verify what gets bundled for the client-side. You'll notice that getServerSideProps/getStaticProps gets removed as do the imports used by it.
Outside of getServerSideProps/getStaticProps, I found 2 fairly similar solutions.
Rely on dead code elimination
In next.config.js:
config.plugins.push(
new webpack.DefinePlugin({
'process.env.RUNTIME_ENV': JSON.stringify(isServer ? 'server' : 'browser'),
}),
);
export const addBreadcrumb = (...params: AddBreadcrumbParams) => {
if (process.env.RUNTIME_ENV === 'server') {
return import('./sentryServer').then(({ addBreadcrumb }) => addBreadcrumb(...params));
}
return SentryBrowser.addBreadcrumb(...params);
};
Note that some for reason I don't understand, dead code elimination does not work well if you use async await, or if you use a variable to store the result of process.env.RUNTIME_ENV === 'server'. I created a discussion in nextjs github.
Tell webpack to ignore it
In next.config.js
if (!isServer) {
config.plugins.push(
new webpack.IgnorePlugin({
resourceRegExp: /sentryServer$/,
}),
);
}
In that case you need to make sure you will never import this file in the client otherwise you would get an error at runtime.
You can import the third party library or a serverside file inside getServerSideProps or getInitialProps since these functions run on server.
In my case I am using winston logger which runs on server only so importing the config file only on server like this
export async function getServerSideProps (){
const logger = await import('../logger');
logger.info(`Info Log ->> ${JSON.stringify(err)}`);
}
You can also import library/file which has default export like this
export async function getServerSideProps(context) {
const moment = (await import('moment')).default(); //default method is to access default export
return {
date: moment.format('dddd D MMMM YYYY'),
}
}
I have the following imports:
import { default as service } from "../service";
VS
import * as service from "../service";
My service is exported like so
module.exports = {
init(store) {
_store = store;
},
beginPayment() {
}
};
I would expect that only the second import would work since there is no export default, however both seem to work.
What is the difference between these? Is one preferred over the other?
If this is a duplicate I apologize, I didn't find anything specific to my example on SO or Google.
If you are importing the default, there has to be a default.
In general, the community appears wary of default exports at the moment as they seem to be less discoverable (I have no specific citation, but I've watched the conversation!)
If you are working in a team, whatever they say is the correct answer, of course!
So without a default, you need to use:
import * as service from "../service";
Or choose a specific thing:
import { specificNamedThing } from "../service";
I have lots of code like this scattered around index.js files throughout my React Native project:
import Restaurant from './Restaurant';
import Store from './Store';
import Vineyard from './Vineyard';
import Wine from './Wine';
export {
Restaurant,
Store,
Vineyard,
Wine
};
It's very repetitive and tedious to write out. Is there a way I can automatically re-export all of the other files in the current working directory from index.js? (note I'm also using Flow in my project so any solution should preserve the type information it can infer.)
Thanks.
export * from './Restaurant';
export * from './Store';
By using the above syntax, you can access all exported properties from each component and export them directly.
This is a common pattern when you grouping all Actions in each individual Action file inside index.js and exporting them directly. You can have a look at the github repo
You can also use this pattern if you'd like:
export { default } from './Comp'
export { default as CompHeader } from './CompHeader'
export { default as CompContent } from './CompContent'
// Usage
import Comp, { CompHeader, CompContent } from './component/Comp'
import { Injectable } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
#Component({});
export shellModule{}
This is a piece of code form my Angular app that I copied from somewhere (I have removed the definitions in the exported module. I am using it to make a service to call APIs.
In the imports in this particular file, why is it that Observable is imported separately even though the entire rxjshas been imported. If a particular module is being imported in its entirety, why is a particular object from it imported separately? I tried asking this question at the forum from where I took it, but there was no answer. I want to understand if this somehow helps with optimization of code.
In general:
In Typescript, the way modules are handled would require you to either load in the entire library with the import * as rx from 'rxjs/Rx', or a specific exported module within the library to use it, so the the compiler loads in the types.
Reducing your imports to only the specific modules you need sets up your app to use tree shaking from Angular's AOT compilation. This is not done by the typescript compiler, but by a tool called rollup. So, it can help with optimizing code later, but it doesn't automatically do so.
As far as compilation overhead, bringing in the whole library might slow down the compiler a bit... but this isn't a very strong point except for massively complex libraries.
I, personally, prefer importing in specific modules because it makes the calling code a little cleaner since I don't need to use that global name to get to the specific name. rx.Observable vs Observable. A good example of this is the lodash library (rxjs is a bit more complex...)
Honestly, importing entire libraries like the line you have there: import 'rxjs/Rx' doesn't make sense to me. You should only import specific exported modules. Try removing it, seeing what errors you get, and then using the * as rx syntax instead.
As far as rxjs goes - it is a little wonky when you want to import specific operators like this question does - so the way to get specific operators is with: import 'rxjs/add/observable/from' - but that also requires a tinkering with your webpack set up as outlined in the referenced question's answer.
Let's see what the rxjs/Rx module exports:
export { Subject, AnonymousSubject } from './Subject';
export { Observable } from './Observable';
export { Operator } from './Operator';
export { Observer } from './Observer';
export { Subscription } from './Subscription';
export { Subscriber } from './Subscriber';
export { AsyncSubject } from './AsyncSubject';
export { ReplaySubject } from './ReplaySubject';
export { BehaviorSubject } from './BehaviorSubject';
...
import './add/observable/bindCallback';
import './add/observable/bindNodeCallback';
import './add/observable/combineLatest';
...
So it exports RxJs classes and also imports operators from the add folder. So as you can see it loads everything in the library. It doesn't export any global object though. So you need to use named export like this:
import * as Rx from 'rxjs/Rx'
to be able to use an exported class:
Rx.Observable.of(12, 3);
This emulates what you would have if you loaded the library using the bundle - a global Rx object:
<script src="rxjs/bundles/Rx.js">
If you want to use Observable without Rx global object, you need to import it separately:
import { Observable } from '#rxjs/Observable';
Observable.of(1);
Importing both
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
is not a good practice, but may be used if you don't want to import every operator separately.
Also see How to correctly import operators from the rxjs package.