ES6 imports and node_modules hell - javascript

i am learning react and writing my own components but i ran into an issue with project organisation.
here is my tree
Project_Folder
- Components
- Form
- index.js
- form.less
- package.json
- Button
- index.js
- button.less
- package.json
- node_modules
- <million unknown packages>
- application.js
- webpack.conf.js
In my application.js i import form like that: import Form from './Components/form/index.js'; Recently i figured if i just put my components folder in to node_modules folder i can import my components with import Form from 'Components/Form'; which is much better. but then developing this components becomes a hell just because whenever i go in to node folder it has millions of other modules which are required by webpack or babel or mini-CSS-extractor.
is there any solution to a better organization within node_modules, or maybe i should install dev tools globally ?

Definitely you shouldn't keep your components in node_modules catalog, that's where you keep only dependencies of your app. Here's might be a good read for you. Especially when you'll be using git repository, you shouldn't copy your node_modules catalog in there, because, as you've noticed - it's huuge. Let any other person working on this code to install dependecies on it's own, after cloning a repo.
There's few conventions - one will be to keep your components in src/ catalog. My advise for you will be to install globally create-react-app (a boilerplate generator for React sites, available here) and check it's conventions. Should be a great lesson for you.
One thing that concerns me is why there's package.json inside each component? There should be only one package.json file for a whole project. Read here.
If you want your file paths shorter and easier to read/use, you can create aliases with Webpack like this.

It is not a good idea to have your components inside the node_modules folder. Unless you are creating shareable code between teams through other tools/frameworks. Using your components there create a whole bunch of a problems that you have not faced YET :( !
i.e Node modules give the flexibility to share code using only the package.json and ignoring them with .gitignore. And reinstalling them through npm install.
Can you see the problem here?
To be able to share your components now inside the node_modules the options are:
either push your files without the folder losing your components (Not an option after all :()
send the whole application and the modules which could be huge and forces everyone to have to download a massive repo or even in case of upload to the repository (git, bitbucket, gitlab) (taking forever to upload)
create a whole module for that component only to write './X' into 'X' (requires extra effort and does not sound a good deal for me)
Structuring folder is a delicate topic. It envolves a little bit of analysis of what suits your taste better and there is no right way of doing (even if you find experts that claim that such way is the correct)
For a better approach you could check the react documentation:
https://reactjs.org/docs/faq-structure
and a tutorial that I think will suffice in your case
https://medium.com/hackernoon/the-100-correct-way-to-structure-a-react-app-or-why-theres-no-such-thing-3ede534ef1ed
Goodluck:)

You should avoid messing with your node_modules folder. It is best to let npm or yarn write into it.
What will happen if you need to delete your node_modules and rebuild it? All your code will be lost.
What will happen if you want to share your code or push it to remote repository.
You will be force to share your nodes_modules folder around.
As for react project best file structure, checkout this article on react website.
There is not really a best structure, all depend on you and your team. Usually people:
Group files by feature
common/
Avatar.js
Avatar.css
APIUtils.js
APIUtils.test.js
feed/
index.js
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
FeedAPI.js
profile/
index.js
Profile.js
ProfileHeader.js
ProfileHeader.css
ProfileAPI.js
Group files by type
api/
APIUtils.js
APIUtils.test.js
ProfileAPI.js
UserAPI.js
components/
Avatar.js
Avatar.css
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
Profile.js
ProfileHeader.js
ProfileHeader.css

Related

Is there a way to specify JavaScript dependencies for git submodules?

I've been working on a website which is a collection of single-page applications. I have a monorepo consisting of my applications in separate directories, and each app has it's own package.json.
In addition to this, each application contains one or more git submodules, where I place my core libraries (ex. one for the "common" lib, one for SVG, etc.). I'm overall happy with this setup. It works well with tooling, since the submodule is directly within the app directory, and makes it easy to version the code.
EDIT: An example directory structure, where "common" is the git submodule:
frontend/app1/common
frontend/app2/common
That said, the biggest flaw has been dealing with dependencies, as sometimes there are dependencies I would like to have across all applications. Since every app has its own package.json, this means that I have to manually install that dependency across all my apps, should I ever use that dependency in my common lib.
What I'm looking for is a way to split a package.json, such that I could (for example), point the app's package.json at the common lib's (hypothetical) package.json, and inherit its dependencies. I'm aware that this is not possible with package.json, but I can't help but feel this is common enough an alternative might exist.
I know Yarn workspaces provides the ability to create local packages, but this wreaks havoc with the project tooling and makes it more difficult to make quick code changes.
Are there any good workarounds that don't involve building some hacky templating system?
My stack is:
Vite
Svelte
Yarn (with workspaces)
Let's say you have these folders:
- app1
- app2
- common
And in common folder you have package.json with node-fetch package, for example.
Also, in common you have index.js with something like this:
import fetch from "node-fetch";
export const getPage = async (page) => await fetch(page);
Then in app1 you have app.js with:
import { getPage } from "../common"
const data = await getPage("http://x.com");
Now all you have to do is to run npm install inside of your common folder.
It can also be a git submodule, doesn't matter. You don't need to add node-fetch into your app1 to get this working.
You might also face another issue: too many package.jsons. For which I wrote a script based on listr that finds all of them recursively and runs npm install or npm test for all of them in parallel. It's not published yet, but I can share some snippets if you're interested.

Other way to share react ts components between projects

I have been looking for a way to mostly share some code between projects specifically for SPFX and fluent ui. We found 3 main ways to do that.
1.
Creating a component library is the way that seemed least complicated cause it uses the same infrastructure and do all building without the need to configure it.
But this adds some issues, we need to built and manually link the solution locally to make it work, this will also work if we put in a repo. so this is mitigated.
The second is that implicitly this will also require the fluent ui and react. Plus having to place it inside a SPFX component library project.
2.
I saw some promise using paths in ts and this works fine while using the ts compiler. It will go to the folder that your proj is referring and build it at calling time. which is great. But it did not work in SPFX.
3.
Another way was to have a post install to sync the folders which seems easy enough but I wonder how practical this is plus how people are doing it, if they are, how.
All I wanted to figure out now is a way to take my component code and share as if they were in a folder of my src or a simple extension of the code. No need to have extra dependencies or build steps, just the code that can be used as a ts/tsx file. ex:
shared lib:
//assuming I have react and fluentui already installed for the project.
import button from 'fluentui';
export const fancyCustomButtom = (props) => {
return (<Button text="Standard" />);
};
src project folder:
import {fancyCustomButtom} from 'shared-lib'
It is fine if it needs to build the files before we can use it but can we do it at build time or when the package is installed? also wouldn't it increase my bundle size by making both module dependent on things already available (react, fluentui)?
Given the way Microsoft have architected the loading of bundles in SharePoint and Teams - I believe an SPFX component library is the best way to share code between different solutions, particularly if you are looking to minimise bundle size...
Imagine you have a library for something re-usable: a form, a set of standard branded components - something of that nature. You could put your shared code in repos and add references to it - either by publishing your own repo publicly or using the npm install git+https://yourUrl syntax; but what effectively happens there is that your code is pulled down in to node_modules for each project, and any referenced module code is included in your bundles. If you have two, three, four or more webparts on the same page - using those same libraries, you're multiplying how many times that code is included on the page.
If you follow Microsoft's guide on setting up a component library project however, your npm link commands allow your types to be recognised in consuming projects without needing to actually include the bundled distribution code. You can deploy your library code once to the App Catalog, and if it's referenced in other solutions -- it's loaded on pages as needed: once.
I have found the development experience to be quite flaky at times, but it does work. When I run gulp clean on my library code, or come back to it after some time, I sometimes find that I need to run npm link and npm link my-project-name again as per the instructions in the above tutorial. Whenever you run gulp build on your library, you should also rebuild the project that consumes the library, either by using gulp build / bundle or by saving a file (if you're running gulp serve). This process works well for developing, and once it comes time to deploy, all you need to do is add a named reference to your library inside package.json and then deploy both .sppkg files to your App Catalog.
In terms of your last question re: bundle size - react is not actually included in the dependencies for an SPFX library project, but you will find it's available to use. When you build your library, if you take a look in the generated javascript in your dist folder, you will see it's listed as one of the dependencies for the webpacked content along with react-dom and ControlStrings. It's on line 1.
office-ui-fabric-react is included as a devDependency thanks to the #microsoft/sp-webpart-workbench package that gets scaffolded with all SPFX projects - and if you check your library's dist javascript, you will see that included components are being webpacked and included in your bundle. I'm not entirely sure if when you pull this code in to your consuming project, whether webpack then tree-shakes to de-duplicate and ensures only necessary code is included: I don't know. Someone else may be able to illuminate us there or provide a more accurate explanation of what's going on... I will update this response if anyone comments to let me know.
And finally, this is more of a personal way of working, but it may be worth consideration:
When developing a library, I sometimes reference it in other projects via a local npm install ../filepath command. This ensures that when I install the library as described, the consuming project installs any necessary dependencies. I'm able to tweak both projects if I need o. When it comes time to deploy, I commit my changes to both projects, deploy my library code to the App Catalog, and then npm uninstall the library from the consuming project and add a reference as described in the above tutorial. When I deploy projects that use my library, they just work.
I recently developed a library that uses pnpjs, in particular the #pnp/sp library that is used to talk to SharePoint. If you look at the Getting Started guide for that library, they expect you to pass a reference to your Application Customizer or Web Part context during setup, or explicitly set things up using a base URL and so forth - and of course, a library doesn't really have a page context of any sort - the whole point of this code is that it's reusable. So that poses a challenge. My solution was to do the setup in the consuming web part(s) and ensure that they pass a reference to the sp object (which is of type SPRest) to any code or components that exist in my library. My library has peerDependencies on those pnp libraries so that the code isn't duplicated in consuming projects. Sometimes you have to think about what your library needs to include in its bundle and what you expect consuming solutions to already have, and maybe find ways to ensure things aren't included that aren't needed.
For example, in the scenario you talk about, you may want to ensure fluentui or office-ui-fabric-react are only devDependencies or peerDependencies for your library. As long as your library and the project(s) consuming your library both use the right version(s) you shouldn't have any trouble, and you can document any pre-requisites with your library documentation. You can check which versions of these libraries are installed per the SPFX version you are currently using ie. SPFX v1.11 or v1.12 etc. Just run npm ls <packagename> to get a breakdown, or check your package.json file.

How to publish typescript ReactJS component on npm?

I would like to make a new ReactJS component with Typescript and publish it on npm.
My idea is to have only a project folder with:
/dist build for final distribution on npm
node_modules
/public where I will have my index.js to locally run my app for development purposes and one folder components where all files for my distributed component will be stored (only component folder will be published)
and other files like .gitignore, .npmignore, package.json and so on..
Something like this:
I have seen many guides (and spent many hours) figuring out how to publish a ReactJS component like:
Create an NPM Package from a React Component
Create a React Component Library using TypeScript
How To Make a React Component Library - Making A React Library
Publish A React Component On NPM
create-react-library
But most of them have such a complicated structure (like script files, babel files, webpacks ..) and generated files that I don't understand.
My idea was to use react-script to run and develop the app locally and then run tsc to compile my component to build. I thought that I don't need create-react-app/library, babel or webpack to publish a react component - if they are necessary, why do we need them? I just thought it should be possible to do it simply and lightly - like just to take tsx files compile them into js..
To me, it seems that the process of publishing a ReactJS component library with TS to npm is not that well documented. Can you please provide steps or some well and easy-to-understand guide on how to publish react component? Also with all the configurations (configuration files), since I think I messed it somewhere there.
Thanks in advance!

Share common typescript code across node projects

Assuming I have the following project structure:
webapps
ProjectA
SomeClass.ts
Package.json
ProjectB
SomeClass.ts
Package.json
Common
LoggingClass.ts
Package.json
The Common "LoggingClass" need to import a module from NPM. Let's assume that module is UUID (https://www.npmjs.com/package/uuid)
The problem, or the challenge is the following: We want to use and import the "LoggingClass" in both ProjectA and ProjectB.
Thing is, they can import the code from the common folder without a problem, but then the module "UUID" is not existent in those project because we did not specify so in their own respective Package.json.
I do not want to create actual node modules since my code needs to be checked into a git repository. (Some people recommend to develop directly into node_modules directory).
I would like to know what other fellow typescript developers do in the community to share their code when using npm. (If it was only typescript files it wouldn't be a problem, but because of the dependencies we have on npm.. it gets complicated).
Any thoughts would be greatly appreciated !
I do not want to create actual node modules since my code needs to be checked into a git repository.
A real npm module is actually a way to go IMHO. You don't have to store it specifically in npmjs.org (you can have an own npm repository).
Some people recommend to develop directly into node_modules directory.
This is actually the most inconvenient way I can imagine of. Probably, I'm missing something important, but I'd love to know their way of thinking.
There are things you will not be able to [easily] achieve with git-only based solution. For example, how would you checkout a specific version of the shared code, with keeping the rest of the code intact? It is relatively easy when you have only one directory where all the shared code lives. But if you have many (basically, directories-as-packages) then it gets cumbersome. And even figuring out their "versions" is tricky too -- you'd have to invent and follow a git tagging rule or some other way to annotate commits.
Anyways, what I am trying to say is that my answer is not exactly what you asked for; my answer is rather a suggestion to reassess you position regarding (not) packing code into an npm module -- which is de facto a standard in the JavaScript/TypeScript community for a reason.
I would like to know what other fellow typescript developers do in the community to share their code when using npm
Since your requirement I do not want to create actual node modules since my code needs to be checked into a git repository.
I would simply reorganize as
webapps
package.json
projectA
SomeClass.ts
projectB
SomeClass.ts
Package.json
common
LoggingClass.ts

setting up development environment (node_modules duplication)

(I am an Actionscript developer finally migrating to JavaScript and am learning TypeScript and AngularJS 2. Let me know if this question is too stupid/naive and I will delete it)
I'm running through the Angular 2 tutorials and all is well but I am wondering about how one typically sets up a development environment without duplication of, for example the "node_modules" and "typings" directories. I understand that the tutorials want to be complete in themselves so there is duplication. I also get that, for example, the line below is using a reference relative to the project folder so it could point someplace else.
Is there a "best practice" for avoiding duplication of node modules? I ask because the "node_modules" directory is 145 mb.
import {Component} from 'angular2/core';
node_modules being duplicated in each project is by design - the idea of having a package.json file and a corresponding folder of dependencies is so that your project is self-sufficient/isolated and does not rely on the environment it's being used in.
That said, you can install NPM modules globally using the npm install [package] -g command, but here's a practical example of why you probably shouldn't - say you have an ongoing project that uses an old version of Angular 2, and you want to start a second project using the latest features. If you're using a global Angular install, this isn't possible; updating the version would update it for every project that's using it (which could horribly break your old app). If you have a separate install per-project, their versions can be different without causing any issues.
This also comes in handy when committing your project to version control - if your entire app relies on globally installed modules and you (or a contributor) wants to work on it on another machine, they'll have to go through and install every single dependency manually so that the environment matches the one it was originally developed in. Compare this to having your dependencies listed in package.json and your node_modules folder excluded from the repo - they just have to run npm install and NPM will install all the relevant modules for them.
I admit that the size of node_modules can get excessive at times, and I hope they optimize this at some point - but I don't think this is a good reason to throw out all the benefits keeping it separate gives you!

Categories

Resources