Angular2 modular system break of modularity - angularjs

I present you the following code:
https://plnkr.co/edit/xxNW1xAIPoGtTK84OxGq
NOTE: This does not work because of SystemJS which I just can not configure. Whoever wants can edit if freely to make it work. I have been using the angular-cli and default webpack config and this works.
My question is about the "AlertService" which is needed to display an "alert". It has been extracted in the core module. However when I need to use it I have import it like so import { AlertService } from '../core/alert/alert.service' as present in dashboard.component.ts in order to inject it.
Doesn't this break the modular approach since I have to give it the path to the class ? If I change the location of the AlertService within the CoreModule I still have to go and change the string in the DashboardComponent. Also in this example if AlertService is not present DashboardComponent will not fire ... but DashboardComponent is part of the DashboardModule which should be able to start on its own - otherwise what is the point of the modules if they are coupled statically I could just put everything in one place.
What I want is to create a general alert component which I only need to include and once in the whole app and be able to use it everywhere.
But I think I am misunderstanding the concept of modules and/or how to use them. I have read the Modules' section in Angular.io multiple times and gone through multiple tutorials.
Best regards

If having to change lots of file paths bothers you a lot, one possible solution is to add another layer - create a services.ts file, then have the canonical imports there rather than in each component. That way, you only have to update one file if you change the path:
services.ts:
import { AlertService } from './alert.service';
// ES2015 shorthand property initializer
export default {
AlertService
};
yourComponent.ts:
import { AlertService } from "../services";
...
If you want a component to work even if a service is not present, you can make it an optional dependency (returning null if it doesn't exist), but TypeScript forces you to still have to import the service into the file to get code completion/typings. That's always felt a little janky to me.

Related

Configuring Jsx-control-statement codesandbox.io

I am practicing react on condesanbox.io installed jsx- control-statement dependency. When iam adding any of the control statement it is undefined.
How to configure jsx- control-statements in codesandbox.io.
This question might be couple of month old and its look like the questioner has not find the solution yet,so here is my fix
Solution: Instead of using just jsx syntax inside the return statement wrap the jsx with react fragment,below is the example
return (<>
{user ? <Component1/>:<Component2/>}
</>)
You will not be able to use jsx-control-statements in codesandbox.io in the similar way that you might in a local babel environment.
(i guess strikethrough isn't a thing on stackoverflow?) ~~You will have to import { If } from 'jsx-control-statements' to get access to the If tag, for example.~~
edit:
I've seen people import it in the past (similar to this example https://github.com/PedroBern/react-tiger-transition/issues/2 ) but, as I'm sure you're aware, the jsx-control-statements lib is a babel plugin; the code seen in that example is probably only serving to calm eslint in an older version of control-statements.
If you pull the jsx-control-statements dependency into codesandbox and cast it to a variable via import whatever from 'jsx-control-statements', and look at 'whatever', you'll see that it is a function. (see the link below for the full code.)
You COULD maybe go down the road of hackifying a dumbed-down version of babel-core, and passing it into whatever(babel) but you're better off creating your own If tag that has a condition property and conditionally renders children.
https://github.com/AlexGilleran/jsx-control-statements/blob/master/src/index.js

Global es6 module to store constants in react app - prevent garbage collection

I would like to store some variables inside a module (export) to be used as constants though out my react app. I would like to avoid context because there is no need for components to re-render and also I need those constants to be used outside my react components.
Where should I do it (where to import it), in order to prevent garbage collection?
One idea I have is to import and re-export it on top of my root component.
EDIT:
To be more precise, there will be a component that will set the constant once (mutate the variable), so that other components or files can access it.
So, what you will need is some sort of setter/getter pattern. Though I mostly don't recommend it unless you know what you are doing, because React won't re-render if the variable changes and because of that you need to be sure the variable is set before it is used.
You should have something like the example below in order for it to work the way you want. You can find an example of it working on this Codesandbox.
export let MY_VARIABLE = "";
export const setMyVariable = value => (MY_VARIABLE = value);
PS: I've added some console.log to the code in order for you to see how the import/get/set behaves.
After digging more into this I found that es6 module spec states:
When import your module it gets loaded => parsed => evaluated and cached (singleton). It also says that when you import modules its value is passed by reference (aka assignment). I didn't find anything mentioning when or how es6 modules are unloaded from that cache.
So that means, when you import a module once, it is there for as long as the program is running, and all modules access its values directly.
reference
https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/
https://medium.com/#mivanichok/understanding-es6-modules-in-depth-article-b49612926e39
You can create an config.js inside src folder and write the your constant variable like
//config.js
module.exports = {
CONST_VAR : 'const value',
}
import config.js in your component and use it

How to export module properly so vscode can show my module in suggestion [ctrl+space]?

I have a setting style file like:
GlobalStyles.js
export const GlobalStyles={
ViewContainer:{flex:1, justifyContent:'center', alignItems:'center'},
Center:{justifyContent:'center', alignItems:'center'},
FontNormal:15,
FontMedium:18,
FontLarge:28,
FontHeader:38
}
module.export={GlobalStyles}
and when i used it in another JS file, let say Home.js. i want to vscode know every Key:Value i've defined,
with those export in GlobalStyles.js vscode suggesting an import style like this:
import { GlobalStyles } from '../Component/GlobalStyles';
and my expected result is something like:
import { ViewContainer, Center, FontMedium, [and so on]} from '../Component/GlobalStyles';
how to let vscode suggesting me Auto Import foo from path/to/GlobalStyles when i'm typing foo? where foo is like ViewContainer, Center, FontMedium, [and so on].
The feature you're talking about is called Auto Imports. To answer your question, this feature exists and works by default in VSCode.
Here is a sample of how i've used it in a React project. Here I have a component inside a folder with the same name. Outside of that folder is a file I called ModuleExports.js and it currently has the following code.
import Navbar from "./Navbar/Navbar";
export { Navbar };
For reference, export is an alias of module.export so feel free to use them interchangeably. This is a component so when I try to use it as such you can see from the screenshot I am suggested an import to use.
The same can be done without being a component. I'll declare a testObject inside the same file ModuleExports.js and export it.
Then let's see if intellisense will pick it up.
There it is. I hope this helps and do ask if you want more clarification or are running into issues.
In this case, the mistake seems to be using dynamic export. That's old CommonJs style. VSCode uses typescript tools for static analysis. To take advantage of that, you have to use ES6 export.
CommonJs: module.export={GlobalStyles}
ES6-modules: export GlobalStyles
The significant difference between two is that CommonJs variant is simply variable which is defined at runtime. Ie. there is no way to know what you are exporting without executing the code. ES6 export is reserved word. It's construct which cant be changed after definition which also means, it's type definition can be found without actually executing the code.
Typescript, Babel etc provide interoperability between two module systems but they are two very different things by spec.

Why do I have to use "require" instead of "import from" for an image in React?

I see that this answer suggests the syntax for importing images as shown below (commented out). In my case, it didn't work out (complaining there's no modules to find in that file) and I had to switch to the syntax that's currently active.
// import Author from "../assets/author.png";
var Author = require("../assets/author.png");
The difference I can imagine is that I'm using TypeScript (transpiling my TSX by awesome-typescript-loader and loading my PNG file-loader) and they seem to use JSX. But as far my understanding goes, it all transpiles to plain JS and require in the end.
Being a noob on React, I'm not sure what the reason of this discrepancy is but also I'm not sure what to google for to investigate myself.
This is more of a problem with typescript than webpack itself, you might need to declare modules on a declaration file.
Create a declarations.d.ts
Update your tsconfig.json
"include": [
"./declarations.d.ts",
],
Put this on that file:
declare module '*.png';
Error might be gone.
You can declare a module for your images like this:
declare module "*.png" {
const value: any;
export default value;
}
Then, you will be able to import your image like this:
import AuthorSrc from "../assets/author.png";
This is happening because webpack doesn't support image import out of the box. So you need to add a rule for that in the webpack config file. When you add a new rule, TypeScript doesn't automatically know that, so you need to declare a new module to resolve this. Without the module, you will be able to import images, but TypeScript will throw an error because you didn't tell to it is possible.
This issue has nothing to do with webpack or any bundler and is not quite a problem with typescript.
Typescript has stated that `require("path") is a way to include modules to the scope of your current module, whilst it can be also used to read some random files (such as json files, for example).
As Vincent and Playma256 specified, you can declare a module wildcard to match certain file types, so you can import it as an import statement. But you don't really need to do this. Typescript won't give you an error if you are trying to import a png or a json file (tslint might, but that depends on your configuration).
By the way, if your declaration is within the source folder of your project as defined in tsconfig.json, you don't need to include it as specified by Playma256.
I've created a sample project in node for you to test:
https://github.com/rodrigoelp/typescript-declare-files
I think you can solve this problem with Webpack&&typescript.The official webpage of webpack has introduced something about this in
https://webpack.js.org/guides/typescript/
And I have try this myself in
https://github.com/reactpersopnal/webpack-root/tree/feature/typescript
The reason is that you would like to use non-code assets with TypeScript, so we need to defer the type for these imports for webpack.
Your could simply add custom.d.ts.
declare module "*.jpg" {
const content: any;
export default content;
}

Why do you need to import React multiple times in parent and child components?

If you have a parent component file that already imports React, why does any of its rendered children files also need to import React? Is it just a safety measure in case those children are ever rendered somewhere else where React has not been imported yet?
In nodejs each file is a module, that has its own scope of variables. When you import variable into file (React for example) you add this variable to the module scope, but not to the global scope.
In case of webpack you can use providePlugin to easily make React variable global:
new webpack.ProvidePlugin({
React: 'react' // ReactJS module name in node_modules folder
})
After that you are able to skip importing React variable in all of your modules. Webpack will do it itself where needed.
If you use JSX and babel, you have to import React in every file because babel-preset-react will transpile your JSX code into React.createElement() calls, so this code
const Foo = () => <h1>Test</h1>;
will be
var Foo = function Foo() {
return React.createElement(
"h1",
null,
"Test"
);
};
DEMO: Babel REPL
This is the reason why React should be accessible in the proper scope and one way to do it, is to import React in a file.
The root of the question is one of dependency management -- how do I, the author, describe and obtain external dependencies I need in my "thing" (application/component/module) for it to do its job?
JavaScript benefits (or suffers) from having a global namespace in which dependencies can be injected. While this can often simplify dependency management in the short term (e.g. you can ignore it and expect everything you need to be available in the global namespace), it can often cause issues as an application grows and changes. For example, given an application with multiple contributors, one might decide to change a part of the application to no longer use a particular dependency and therefore remove it. If another part of the application needed it but that dependency wasn't formally declared anywhere, it could be easily missed.
To do dependency management well, each discrete "thing" should describe its dependencies independent of any other "thing" such that it can be safely used in any given context. This ensures that each "thing" has exactly what it needs no matter how it is used and what its "parent" (the code importing the "thing") has.
An alternative to this approach is dependency injection. In this model, the "thing" provides an interface for passing the dependencies into the "thing" from the consumer. There are flexibility and testability advantages to this which are out of scope of your question. :)
// export a function that expects the React and PropTypes
// dependencies to be injected as parameters and returns
// the component rather than importing the dependencies
// and exporting the component
export default (React, PropTypes) => {
return class extends React.Component {
static propTypes = {
name: PropTypes.string.isRequired
}
render () {
return (
<div />
);
}
};
};
All of that to say, it is somewhat a "safety measure" to have each "thing" import its own dependencies. It lets you safely refactor your code without the cognitive overhead of remembering what is providing those dependencies.
The reason is to avoid unnecessary compiled a JavaScript code that you don't have to compile jsx. For example, you have a file that have a function to do adding, or whatever function that doesn't need to compile jsx, then you don't put import React from 'react' on the top of that file. This will save you compile time.

Resources