Manage global aliases for multiple npm packages - javascript

I have 3 npm projects, all exists under the same root folder. The projects are more complex than the example below (using webpack, JS frameworks, etc.) but to keep it simple for illustration purposes this is the structure:
root
├── root_index.js
├── package.json
├── project_1
│   ├── index.js
│   └── package.json
├── project_2
│   ├── index.js
│   └── package.json
└── project_3
   ├── index.js
   └── package.json
My problem is I find lots of situations in the code where imports, for example from project_1 to project_2 contains lots of '..', for example - '../../../../project_2/some_module'.
Would be nice if I could define a global variable '#project_2' that will point to the project and then I could change my imports to '#project_2/some_module'.
I saw webpack offers some solutions for aliases but I don't use webpack in my root folder, only in each project individually and so I cant use its configuration to control all projects from a single point. I also found this 'module-alias' package but it didn't work properly together with the configurations (mostly webpack) I have in each of the projects.
any idea how can I define these global variables so I could use them in each of the projects?

It sounds like you want to set up your project as a mono-repo.
I would recommend you to use the yarn workspaces concept and Lerna to help you manage it.
What is mono-repo?
In short, a so-called Mono-Repo is a (git) repository that houses multiple projects. Such projects are called workspaces or packages.
Lerna is a tool that optimizes the workflow around managing multi-package repositories with git and npm.
checkout official website: https://lerna.js.org/
Attaching a good article to help you start with yarn workspaces and lerna:
https://medium.com/hy-vee-engineering/creating-a-monorepo-with-lerna-yarn-workspaces-cf163908965d

Related

Jest + React Native, how to configure iOS and Android unit testing from scratch?

I have a Lerna monorepository with a Web application and a module:
.
├── apps
│   └── id-check-app <# Web application (create-react-app)
├── lerna.json
├── package.json
├── packages
│   └── id-check <# Module made with react-native-web
├── tsconfig.json # and compatible with react-native
└── yarn.lock
The id-check module within packages is made with react-native-web, aliased on react-native imports.
So far, we are able to test for the Web but if we use custom version of our components for iOS or Android, then we are not able to test their react-native versions.
I may try to bootstrap a fresh react native application in the apps directory for being able to test them. (Note: we do not use expo)
How can I configure React Native and Jest to be able to test components for iOS and Android our components using the real react-native package?

Imported class in angular is undefined

I have an npm project with the following structure:
app-dep
├── dist
│ ├── bundle.js
│ └── bundle.js.map
├── node_modules/
├── package.json
├── package-lock.json
├── src
│ ├── base-component.ts
│ ├── factory.ts
│ ├── app.ts
│ └── modules/
├── tsconfig.json
└── webpack.config.js
My app.ts code has an App class that utilizes all .ts files inside src/
export default class App extends HTMLElement { //some-content }
I use webpack to build a bundle.js inside the dist/ folder.
I have another angular project where I install this app-dep project using
npm install --save ../app-dep
When I try to use it in my angular component:
import App from 'app-renderer/dist/bundle';
ngOnInit() {
window.customElements.define('micro-app', App);
}
I get this error:
Failed to execute 'define' on 'CustomElementRegistry': parameter 2 is not of type 'Function'
When I try to log it on console, all I can see is undefined.
It seems that I can't import basic functions even.
Can you tell me what's wrong?
I think the problem has to do with the import or the pack, I ellaborate below with the steps to follow.
Also, make sure that you are exporting all the classes that you want to make available from the outside.
For TypeScript libraries
You can simply use "tsc" and then pack the generated code inside the dist folder with "npm pack" and install the dependency in your application with "npm install ".
This may get complicated due to the different module systems and bundlers, check this links for more info on Webpack:
https://marcobotto.com/blog/compiling-and-bundling-typescript-libraries-with-webpack/
https://webpack.js.org/guides/author-libraries/
For CSS libraries
The "npm pack" has to be executed in the root folder. You may want to process your styles with sass before and only pack the result.
For Angular libraries
By default with Angular CLI when you build a library project the code is generated in /dist/mylibrary folder.
If you want to use that code in other project, the steps are:
Build your library with "ng build mylibrary" (add --prod for production).
From your library, move into /dist/mylibrary folder and then execute a "npm pack", that will generate a tgz package.
From your application in which you want to use the library execute "npm install " to install the dependency.
To import code from the library use "import * from 'mylibrary'"
Other option would be using "npm link", that creates a link between your node_nodules and the library code as explained here:
https://www.willtaylor.blog/complete-guide-to-angular-libraries/
That would be the way to go with local libraries, usually these libraries are published into Npm repository (public or private) and installed remotely with "npm install ". These steps are only for local usage.

Sharing Code between Multiple React Applications with Symlinks

I currently have two separate frontend applications. A lightweight mobile client and a heavyweight administration panel. Both were created with CRA. We use TypeScript for everything.
Currently, the directory structure is as follows:
root
├── admin (created using create-react-app)
| ├── node_modules
| ├── public
| ├── src
| │ └── common (symlink)
│ │ └── index.ts
| ├── package.json
| └── tsconfig.json
├── mobile (created using create-react-app)
| ├── node_modules
| ├── public
| ├── src
| │ └── common (symlink)
│ │ └── index.ts
| ├── package.json
| └── tsconfig.json
└── common (linked)
├── src
├── package.json
└── tsconfig.json
For whatever reason, CRA does not respect the symlinks. It's as if no files are even there.
Is there a sanctioned way to do something like this?
Right now, we're copying files into the two repositories with another script. I also tried to use yarn link, but Typescript can't resolve the files properly (it keeps expecting to see a JavaScript).
There is a few different approaches.
You could package it as a library and import said library in to your projects. The library can be hosted on a private or public Git host and reference the Git URL in your package.json just like a NPM package.
"dependencies": {
"your-lib": "git+ssh://git#domain.com:name/repo.git",
}
This approach forces you to push your code and re-install on every change though. And might be hard to work with if changes occur often in your code.
You can also use something like Lerna to organize your codebase in to a multi package repository.
https://github.com/lerna/lerna
I believe the easiest way is to use yarn workspaces (https://classic.yarnpkg.com/blog/2017/08/02/introducing-workspaces/), for this you need to define in root package.json with dependencies, like this
"workspaces": [
"admin",
"mobile",
"common"
]
And then you can use yarn install, and it's should work out of the box.
Before you would try it please, unlink common, to ensure that it works as it should.
Also, you need to have dependencies in admin and mobile on common package.
I'm using yarn link and it works perfectly. The difference could be, that I'm fully building (with rollup) the ts library (common) code.
Tips/tricks:
have "declaration": true in the common package's tsconfig.json
sometimes if the new stuff is not picked up, use Restart TS server in VSCode
have some yarn start build watch running in both packages (for tsc-watch or any other build), this way all changes will be picked up immediately
it could be worth checking ls -ald node_modules/<mypkg> if it really is a symlink, because any other npm install could remove it (yarn seems to be better in this)

Import module from npm to javascript file

I am trying to import showdown module in my home.js file.
The GitHub installation guide tells me to run npm install showdown and presents a simple example of using the module, as such:
var converter = new showdown.Converter(),
text = '# hello, markdown!',
html = converter.makeHtml(text);
I have installed the module using that command, but now I m not sure how to use this module inside my home.js situated under app/static/js path. I tried using require but it s not a solution since
it does not exist in the browser/client-side JavaScript.
Project Tree
├── app
│   ├── __init__.py
│   ├── routes.py
│   └── static
│   ├── js
│   │   └── home.js
│   └── styles
│   ├── main.css
│   └── normalize.css
├── config.py
├── package-lock.json
├── package.json
├── run.py
└── node_modules
Javascript file home.js
const textEditor = document.querySelector('.text-editor')
const preview = document.querySelector('.preview')
var converter = new showdown.Converter() // <- error fires here
console.log('text-editor', textEditor)
console.log('preview', preview)
textEditor.addEventListener('keyup', event=>{
const {value} = event.target;
const html = converter.makeHtml(value)
preview.innerHtml = html
});
Question: How do I import this showdown inside my index.js so that I can be able to use every function of the module?
You can use Browserify for this.
It allows you to use require() for requiring node_modules.
Here are the steps in which you can use the showdown npm package in your project.
Install browserify globally using: npm install -g browserify
Use require() to include your npm modules in your project.
const showdown = require('showdown');
Prepare a bundle for accessing require() function in your home.js usnig browserify:
browserify js/home.js > bundle.js
Include the bundle.js file created in your code using the script tag.
<script src="bundle.js"></script>
Here are some resources that explain how to use browserify in more detail:
https://medium.com/jeremy-keeshin/hello-world-for-javascript-with-npm-modules-in-the-browser-6020f82d1072
https://github.com/browserify/browserify#usage
Additionally, this article also explains well how to choose the tool for compiling your front-end applications based on your requirements. And it contains detailed information about how to use browserify

Failed to get mock metadata (babel 7 upgrade)

I am mocking out a git submodule (which is essentially just a javascript library we use at work), and all my mocks started returning:
Failed to get mock metadata
This happened after we upgraded the git submodule project to babel 7 (from 6). If I go into the submodule and revert the changes back to babel 6 the tests return to passing.
I mock out the module like so:
// path is an alias defined in webpack config
import { MyModule } from 'my-module';
jest.mock('my-module');
MyModule.someAttr.mockResolvedValue({data});
Any ideas why upgrading to babel 7 introduced these errors, everything else (including the submodule) works fine, just the tests on our UI which utilizes the submodule don't pass
The error is related to the way Jest resolves manual mocks. It may be that the import statement is resolved by Webpack with the alias resolver, but the jest.mock() function would not have that alias resolver into consideration. Manual mocks are resolved in the __mocks__/ folders relative to the
Because your mock module is part of a git submodule. You could either set up your submodule directory to be placed in the root of your project inside a __mocks__/ folder or either have the exported module of your submodule dependency inside a __mocks__/ folder.
.
├── config
├── __mocks__
│ └── mock-module.js
├── submodule
│ ├── __mocks__
│ │ └── mock-submodule.js
│ └── index.js
├── node_modules
└── src
Removing jest.mock('my-module'); from my code worked. I've faced this error for vue3-lottie package.

Categories