I've created some functions in JavaScript.
I've found out that I reuse them in many projects.
So I decided to create a small JavaScript Library for my coding.
A Library like react, react-dom, jquery which I can install with npm:
npm install <my-personal-library>
I searched the net. I learned that I can use npm publish <my-personal-library, but I do not know how to format my library and functions to use and install them like an npm package.
Also, I have no idea about creating type definitions for my functions and library.
like #types/react
Any guidence?
About how to publish your library
You can read the official npm documentation on how to create nodejs package modules:
https://docs.npmjs.com/creating-node-js-modules
Basically, what you need is a JS module file (IE test.js) to be exported with exports keyword like:
exports.printMsg = function() {
console.log("This is a message from the demo package");
}
Then publish the module with npm publish (add --access public if you want it to be public)
Finally import the package in the project you need it with npm install <your-module-name>
About the type definitions
I understand that you are using typescript? Then the following link is a good read:
https://www.typescriptlang.org/docs/handbook/declaration-files/dts-from-js.html
To install your package in a pc you have to set up a cli package inside npm module.
import { Command } from "commander";
import open from "open";
// [] indicates that this is optional
// <> indicates that this is a required value
export const serveCommand = new Command()
.command("serve [filename]")
// when user enters node index.js --help, it sees description
.description("ADd a description")
.option("-p, --port <number>", "port to run server on", "4005")
.option("-v, --version", "show version", version, "")
// first arg will be the arg that passed in command() SO filename
// second arg is all other options
// THIS IS WE TELL WHAT TO DO
.action(async (filename = "main.js", options: { port: string }) => {
try {
// this is where you add logic about what to do when enterd the command
open("http://localhost:4005");
} catch (error: any) {
if (error.code === "EADDRINUSE") {
console.error("Port is in use. Try runnng on a different port ");
} else {
console.log("Issue is :", error.message);
}
process.exit(1);
}
});
To make cli run the code, in your main file
//whenever anyone runs cli from command line, this file will be executed.
!/usr/bin/env node
import { program } from "commander";
// this is the above command
import { serveCommand } from "./commands/serve";
// you could chain other commands .addCommand(otherCommand)
program.addCommand(serveCommand);
// parse this and run the aprropriate command that you put together
program.parse(process.argv);
as you see you might have different sub packages and each sub packages will have their own package.json. To communicate between those sub packages, you add them in their dependencies inside package.json. for example, you have to use cli package inside your main package. so in package.json
"dependencies": {
"#my-npm-package/cli": "^1.0.15",
// other dependencies
"express": "^4.17.1",
}
Since you have different sub packages and you have to group them together. Assgin those pacakges into an "organization". another term is to "create scoped package". "#types/cors" and "#types/express" are scoped packages.
Declaring Scoped Packages
in npm page, on the right, cick on "Add organization"
organization name should be unique
update name of the dependencies in package.json of each package.
Manage packages
Use Lerna to manage all of those npm packages. it is for managing multi project packages. - Lerna is one tool out there in the wild that we can use for managing a multi package project. Yarn and Npm are similar to lerna. there are also Bolt and Luigi.
Related
I have the following initial situation:
Our tests refer to a store that is available in multiple languages via country dropdown.
Depending on the country, the store has different features and therefore also different tests.
I have two problems here. The first is the folder structure
In order not to have a separate repo for each country, we would like to separate the test specs for the stores by folders.
But since the PageObjects are identical, I would like to define them only once, so that the test specs can access them.
However, it does not work as I imagine it.
Here is my idea of the folder structure in Cypress:
cypress-automation
cypress
fixtures
integration
shops
shop_de
sample-tests.spec.js
shop_en
sample-tests.spec.js
shop_es
sample-tests.spec.js
plugins
index.js
support
pageObjects
samplePageObject.js
index.js
commands.js
node_modules
cypress.json
package-lock.json
package.json
However, it doesn't work because Cypress misses the PageObjects. The following error occurs:
Error: webpack compilation error
./cypress/integration/shops/shop_en/sample-tests.spec.js
Module not found: Error: Unable to resolve '../support/pageObjects/samplePageObject.js' in 'C:\users\users\desktop\cypress-automation\cypress\integration\shops\shop_en'.
The second problem concerns the index.js
there I have to add a country switch in the beforeEach method, because the URLs of the stores are identical and the store can only be changed via dropdown.
Unfortunately I don't know how to integrate the index.js into the store folder, so that the sample-tests.spec.js access a specific index.js instead of a global one. Alternatively, I would have to adjust the beforeEach method in each sample-tests.spec.js but with so many test specs I find that impractical.
is that even possible, the way I imagine it?
EDIT:
#Fody
i did it exactly as you said. However, now I get an error:
PageObjects_homePage__WEBPACK_IMPORTED_MODULE_1_.HomePage is not a constructor
here is an example from my code how i included it:
import { HomePage } from "#PageObjects/homePage";
the constructor looks like this
const homePage = new HomePage();
HomePage Class:
class HomePage {
testMethod() {
testcode()
}
}
export default HomePage;
For part one, set up a webpack alias to make it easy to import from anywhere in the intergration folders, any level nesting.
Add the package Cypress Webpack Preprocessor, following their instructions
npm install --save-dev #cypress/webpack-preprocessor
npm install --save-dev #babel/core #babel/preset-env babel-loader webpack - if not already installed
or with yarn
yarn add -D #cypress/webpack-preprocessor
yarn add -D #babel/core #babel/preset-env babel-loader webpack - if not already installed
cypress/plugins.index.js
/// <reference types="cypress" />
const path = require('path');
const webpack = require('#cypress/webpack-preprocessor');
console.log('__dirname', __dirname) // __dirname is cypress/plugins
module.exports = (on) => {
const options = {
webpackOptions: {
resolve: {
alias: {
'#PageObjects': path.resolve(__dirname, '../../cypress/support/pageObjects')
},
},
},
watchOptions: {},
};
on('file:preprocessor', webpack(options));
};
cypress/integration/shops/shop_de/sample-tests.spec.js
// resolves any level of nesting
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...
cypress/integration/shops/shop_de/bavaria/sample-tests.spec.jbs
// same import after move to sub-folder
import {MyPageObject} from '#PageObjects/samplePageObject.js'
...
I have a very simple app here where index.html simply imports index.js where:
index.js
import * as wasm from "wasm";
wasm.greet();
lib.rs
mod utils;
use wasm_bindgen::prelude::*;
#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[wasm_bindgen]
extern { fn alert(s: &str); }
#[wasm_bindgen]
pub fn greet() { alert("Wasm is running haha!"); }
package.json
...
"dependencies": {
"wasm": "portal:../pkg"
},
...
Now, here is my issue:
When I use "file:../pkg" in package.json, everything works, but if
I make a change and recompile using wasm-pack it does not update.
Even running yarn install will not update. The only way I can get
changes to show is by running yarn install --check-files but then
the install takes time and it's quite painful.
When I use "portal:../pkg" in package.json instead, I get an error ERROR in ./index.js Module not found: Error: Can't resolve "wasm" ..... This is not what I expect.
When I use "link:../pkg" everything works as planned, and I do not have to run yarn install every-time I compile to see the changes. This is great and what I really want.
Yet, when I read protocols here https://yarnpkg.com/features/protocols the difference between link and portal is only that portal will follow dependencies if package.json exists in my ../pkg folder. In my case, it does, and I expect to have further dependencies there. So how can I get portal to work? And why is it not working now when link is working?
I installed a package called htmldiff by npm install command in my vue project.
Then I tried to import the package in one component
import { diff } from 'htmldiff'; // the package didn't use default export
And I get this error.
This dependency was not found:
* htmldiff in ./node_modules/cache-loader/dist/cjs.js??ref--12-0!./node_modules/babel-loader/lib!./node_modules/cache-loader/dist/cjs.js??ref--0-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/Editor3.vue?vue&type=script&lang=js&
To install it, you can run: npm install --save htmldiff
I can see htmldiff in the project's package.json file.
I can also see that the main file was specified in htmldiff's package.json like this :
"main": "htmldiff.js",
What else should I look at?
The package is faulty.
In /node_modules/htmldiff/package.json the main is defined as htmldiff.js but that file literally does not exist. It would need to be main: "src/htmldiff.js".
Even tho module is installed and it exists, Flow cannot resolve it and throws error.
See below:
1) Inside bash I ran flow and it throws error that module is not found
user#pc:~/code/project$ flow
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/functionalities/Growth/index.js:3:25
Cannot resolve module react-redux.
1│ // #flow
2│ import React from "react"
3│ import { connect } from "react-redux"
4│
5│ type Props = {
6│ children: Function
Found 1 error
2) Below command checks whether directory exists and it does
user#pc:~/code/project$ ls node_modules | grep react-redux
react-redux
I tried to remove and reinstall both node_modules directory and yarn.lock file.
Versions should be matching:
flow version
Flow, a static type checker for JavaScript, version 0.77.0
.flowconfig:
[version]
0.77.0
This is very likely bug with Flow, I also submitted issue.
How to fix it
You have two options:
stub the dependency by hand
bring in flow-typed to find the dependency type
file/stub it for you
I use option 2 but it is nice to know what is happening underneath
Option 1
In .flowconfig, add a directory under [libs],
...
[libs]
/type-def-libs
...
Now, create that directory at your project root and a file /type-def-libs/react-redux which contains,
declare module 'react-redux' {
declare module.exports: any;
}
Option 2
install flow-typed, if using yarn yarn add -D flow-typed
I prefer to install every locally to the project when possible
run yarn flow-typed install
this will install any type definition files for modules that it finds AND it will stub any modules it doesn't find, which is similar to what we did in option 1
Why is this error happening
Flow is looking for the type definition for the module you are importing. So while the module does exist in /node_modules that module doesn't have a type definition file checked into its code.
I had the same issue as you.
I resolved it by using flow-typed
I did the following:
Install flow-typed globally. example: $ npm install -g flow-typed
Then inside your project root folder, run $ flow-typed install react-redux#5.0.x
• Searching for 1 libdefs...
• flow-typed cache not found, fetching from GitHub...
• Installing 1 libDefs...
• react-redux_v5.x.x.js
└> ./flow-typed/npm/react-redux_v5.x.x.js
react-redux
You should see this if the install was successful.
Then try running flow again $ npm run flow in your project. The error with react-redux will no longer be there.
Alternative solution (for some cases)
Check your .flowconfig and remove <PROJECT_ROOT>/node_modules/.* under the field [ignore] (in case you have it there).
UPDATE 1 (by arka):
Or you can add !<PROJECT_ROOT>/node_modules/react-redux/.* after <PROJECT_ROOT>/node_modules/.*. This will ignore all the modules except for react-redux.
Thanks to #meloseven who solved it here.
I checked my package.json file and noticed react-redux was missing. I manually added it to the dependencies "react-redux": "x.x.x" and ran npm install thereafter. Note that the version number should be compatible with the other modules.
Please ensure that you provide the path under 'ignore' in .flowconfig, like this:
[ignore]
.*/node_modules/react-native/Libraries/.*
and not like this:
.*/node_modules/react-native/Libraries/Components
.*/node_modules/react-native/Libraries/Core
....
I want to only allow certain version of node and npm before the user can run his npm install on my module.
In the NPM documentation, there is an engine attribute, dedicated to this task:
"engines": {
"node": ">=4.0.0",
"npm": ">=3.0.0"
}
These parameters will only allow node and npm versions up to 4 and 3.
However, the documentation says that the engine-strict attribute should be enabled in order to check the versions. On engine-strict, it is said that:
This feature was deprecated with npm 3.0.0
So, is there a way, with npm3, to define minimal Node and NPM versions for a module?
Yarn checks the engine out of the box at the time of installation. But with npm, you may have to write a custom validator at this moment for checking node versions before firing a script.
export function verifyNodeVersion(version) {
const nodeVersion = process.versions.node;
if (!nodeVersion.startsWith(`${version}.`)) {
throw new Error(
`Incorrect version of Node found: ${nodeVersion}, Expected: v${version}.x`
);
}
console.log('Current Node version:', nodeVersion);
return true;
}
And call the function in the entry points.
So, is there a way, with npm3, to define minimal Node and NPM versions for a module?
engines does that. It's just that it does it by A) Outputting an advisory message warning the user if their system isn't up-to-scratch, and B) Failing if the user has set the engine-strict config flag.
All the documentation is saying is that engineStrict is no longer supported to push the user around. :-) If they want to ignore the advisory messages and not use the engine-strict config flag, then caveat user.