Add packages to custom #frontend_components or lib folder using yarns - npm

When migrated from bower to yarn and ran the command
yarn install
yarn created #bower_components folder and all the bower/front-end components were add inside this folder ../node_modules/#bower_components
"dependencies": {
...
"#bower_components/bootstrap": "twbs/bootstrap#^3.3.7",
"#bower_components/jquery": "jquery/jquery-dist#^3.1.1",
"#bower_components/lodash": "lodash/lodash#^4.17.12",
"#bower_components/moment": "moment/moment#^2.19.1",
... }
If, I need to create migrate from #bower_components to #frontend_components or add to public/lib folder. How do I do it?
yarn --cwd /public/lib add lodash

The way bower-away works is by creating a symlink from /bower_components to /node_modules/#bower_componets:
bower-away gets away with this by resolving all dependencies with
Bower, and adding all of them flattened to package.json
Then, your package.json file with contain bower dependencies as:
{
"dependencies": {
"#bower_components/bootstrap": "twbs/bootstrap#^3.3.7",
"#bower_components/jquery": "jquery/jquery-dist#^3.1.1",
"#bower_components/lodash": "lodash/lodash#^4.17.12",
"#bower_components/moment": "moment/moment#^2.19.1",
}
}
This will work in most scenarios. But in your case, the symlink is not working. I ran the same issue and my fix was to modify my express server and map /bower_components front-end resource into /node_modules/#bower_components backend resource with the following line:
New
app.use("/bower_components", express.static(path.join(__dirname, "/node_modules/#bower_components")));
Original
//app.use("/bower_components", express.static(path.join(__dirname, "/bower_components")));
If this is not your case, you may need to manually update front-end references to new node_modules/#bower_components folder just as advised as the original author: Adam Stankiewicz
But initially, the only change required in code is to change any
reference to bower_components with node_modules/#bower_components
(though you can link it somewhere else in postinstall script).

The workaround which I implemented to resolve this issue was by introducing a simple script and updating the package.json with a new key.
Under package.json (for all the UI related dependencies needed to work with the front-end)
...
...
"scripts": {
"postinstall": "node migrateUI.js"
},
...
"uidependencies": {
...
"bootstrap": "^3.3.7"
"jquery": "^3.1.1",
"lodash": "*",
"moment": "^2.19.1",
...
},
"dependencies": {
....
"bootstrap": "^3.3.7"
"jquery": "^3.1.1",
"lodash": "*",
"moment": "^2.19.1",
....
}
migrateUI.js
const uipackage = require('./package.json');
const packageName = Object.keys(uipackage.uidependencies);
const dir = 'public/libs';
//if the folder already exists, it ignores else creates.
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
for (let i = 0; i < packageName.length; i++) {
const element = packageName[i];
const source = path.resolve('node_modules/' + element);
const target = path.resolve('public/libs/' + element); //custom lib folder to save all UI dependencies
if (!fs.existsSync(target)) {
fs.symlinkSync(source, target, 'dir', (err) => {
if (err && err.code !== 'EEXIST') {
console.log('Error creating dependecny symlink - ', err);
} else {
console.log('Symlink for dependency created');
}
});
}
}

Related

The keyword 'interface' is reserved when using lerna

I had a react project created using create-react-app which I am now trying to convert to a monorepo architecture. I moved all the independent code in one package, package1 and the rest of the code (along with App.tsx and index.tsx) in another, package2. Also I have added the dependency of package1 in package2.
However, when I try to do yarn start in the second package, I get this error:
Module parse failed: The keyword 'interface' is reserved (11:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
What is it that I am doing wrong in the setup which is causing me this error?
It seems that it is related to tsconfig file.
so change jsx option in tsconfig.json from "preserve" to "react".
run yarn add -W craco within lerna project and
add this to your craco.config.js file within package2
const path = require('path');
const { getLoader, loaderByName } = require('#craco/craco');
const packages = [
path.join(__dirname, '../package1')
];
module.exports = {
webpack: {
configure: (webpackConfig, arg) => {
const { isFound, match } = getLoader(
webpackConfig,
loaderByName('babel-loader')
);
if (isFound) {
const include = Array.isArray(match.loader.include)
? match.loader.include
: [match.loader.include];
match.loader.include = include.concat(packages);
}
return webpackConfig;
}
}
};
and change your package.json file
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
}

Can I find a package's peer dependencies on www.npmjs.com

I have a project that has around 50 packages installed through NPM. After several months of neglect I now need to update most packages, resulting in several mismatching peer dependencies. In order to find the correct combination of package versions I want to see the peer dependencies of all versions of a certain package.
Where on www.npmjs.com can I find a package's peer dependencies?
A package's page shows "dependencies" and "dependents", but I believe these are normal dependencies, not "peer dependencies".
The www.npmjs.com website doesn't expose peer dependencies information. However, this metadata resides at the npm registry endpoint: https://registry.npmjs.org/.
Via your command line you can access it by utilizing the npm view command. For instance:
npm view <pkg_name> peerDependencies
Note: You'll need to substitute the <pkg_name> part with a real package name.
The aforementioned command will list peerDependencies for the latest version of the given package.
I want to see the peer dependencies of all versions of a certain package.
To achieve this you can:
Run the following command to obtain all versions for a given package
npm view babel-loader versions --json
Note Here we check for babel-loader but this could be any valid package name
This will print:
[
"4.0.0",
"4.1.0",
"4.2.0",
"4.3.0",
"5.0.0",
...
]
Then run the following command to obtain the peer dependencies for each version previously listed:
npm view babel-loader#4.0.0 peerDependencies --json
^^^^^^
prints:
{
"babel-core": "^4.0.0",
"webpack": "^1.4.5"
}
Repeat again - similar to before but change the #<version> suffix, i.e. #4.1.0 in the example below.
npm view babel-loader#4.1.0 peerDependencies --json
^^^^^^
This prints:
{
"babel-core": "^4.7.0",
"webpack": "^1.4.5"
}
and so on...
Automate the task:
You may want to consider automating the steps above by creating a node.js script as follows. This utilizes the nodejs execSync() method to shell out the necessary npm commands, however you could change it to utilize the exec() method if you want it to run asynchronously:
script.js
const fs = require('fs');
const sh = require('child_process').execSync;
const PKG_NAME = 'babel-loader'; // <-- Change the package name.
const destFilePath = PKG_NAME.replace(/\//g, '_') + '-peer-deps.json';
const versions = JSON.parse(sh('npm view ' + PKG_NAME + ' versions --json').toString());
const data = versions.map(function(semver) {
const pkgVersion = PKG_NAME + '#' + semver;
console.log('> Fetching peerDependencies info for: ' + pkgVersion);
const peerDeps = sh('npm view ' + pkgVersion +
' peerDependencies --json').toString().replace(/[\r\n]/, '');
return {
name: pkgVersion,
peerDependencies: peerDeps ? JSON.parse(peerDeps) : null
}
});
fs.writeFileSync(destFilePath, JSON.stringify(data, null, 2));
console.log('\nDone !');
Then run the following command to invoke the node.js script:
node ./path/to/script.js
Note: You'll need to redefine the ./path/to/ part as necessary.
Given the value of babel-loader currently assigned to the PKG_NAME variable in script.js you'll see something like the following logged to your console:
> Fetching peerDependencies info for: babel-loader#4.0.0
> Fetching peerDependencies info for: babel-loader#4.1.0
> Fetching peerDependencies info for: babel-loader#4.2.0
...
Upon completion it will write a .json file to disk named babel-loader-peer-deps.json, which includes the following content:
babel-loader-peer-deps.json
[
{
"name": "babel-loader#4.0.0",
"peerDependencies": {
"babel-core": "^4.0.0",
"webpack": "^1.4.5"
}
},
{
"name": "babel-loader#4.1.0",
"peerDependencies": {
"babel-core": "^4.7.0",
"webpack": "^1.4.5"
}
},
{
"name": "babel-loader#4.2.0",
"peerDependencies": {
"babel-core": "^4.7.0",
"webpack": "^1.4.5"
}
},
...
]
EDIT: Reducing the number of https GET requests
If you're wanting to reduce the number of https GET requests to just one then I suggest utilizing the nodejs builtin https.get() to fetch JSON data from the https://registry.npmjs.org/ endpoint.
This example gist below will be much faster.
get-peer-deps.js
const fs = require('fs');
const path = require('path');
const https = require('https');
const pkgName = process.argv[2];
const myName = path.basename(__filename);
// Check the package name has been provided
if (!pkgName) {
console.log('\x1b[40;37m%s\x1b[0m \x1b[40;31m%s\x1b[0m', myName,
'ERR!', 'Missing package name argument');
process.exit(1);
}
const fileName = pkgName.replace(/\//g, '_') + '-peer-deps.json';
const destFilePath = path.join(path.dirname(__filename), fileName);
const endPoint = 'https://registry.npmjs.org/' + encodeURIComponent(pkgName);
// Request JSON from npm registry endpoint.
https.get(endPoint, function(resuest) {
console.log('> Fetching peerDependencies info for: %s...', pkgName);
var response = '';
resuest.on('data', function(chunk) {
response += chunk;
});
resuest.on('end', function() {
processJsonResponse(response);
});
}).on('error', function(err) {
console.error(err);
});
/**
* Processes the JSON response to extract the necessary metadata and saves
* resultant JSOn to disk.
* #param {String} data - The JSON response from the npm registry.
*/
function processJsonResponse(data) {
const versions = JSON.parse(data).versions;
const semvers = Object.keys(versions);
const peerDepsInfo = semvers.map(function(semver) {
const current = versions[semver];
return {
name: current.name + '#' + current.version,
peerDependencies: current.peerDependencies || null
};
});
fs.writeFile(destFilePath, JSON.stringify(peerDepsInfo, null, 2), function(err) {
if(err) {
return console.log(err);
}
console.log('> Done. Saved result to:\n %s', destFilePath);
});
}
Usage:
Then run the following command via your command line tool to invoke get-peer-deps.js:
node ./path/to/get-peer-deps.js babel-loader
^^^^^^^^^^^^
Note: When invoking get-peer-deps.js it's necessary to provide the package name as an argument. In the example above we pass in babel-loader. This can be replaced with whichever valid package name you prefer. For example in the next example we pass in #angular/forms:
node ./path/to/get-peer-deps.js #angular/forms
^^^^^^^^^^^^^^
The resultant .json file will be formatted as described previously and will be save to the same directory where get-peer-deps.js resides.

How to access waypoint shortcuts with bower and gulp?

I have installed waypoints with using bower. I can see that there is a folder for shortcuts inside of its /lib folder, containing the shortcuts for infinite.js inview.js and sticky.js. My question is how I can actually access them in my project using bower.
I am using gulp to package all of my JavaScript for this project, so I am using "main-bower-files" to compile all of the library javascript files into a single file.
I have modified the bower.json so that waypoints will use the jquery version by doing the following
"dependencies": {
"jquery": "^3.3.1",
"waypoints": "^4.0.1"
},
"overrides" : {
"waypoints" : {
"main": "lib/jquery.waypoints.js"
}
}
But I do not know how I can include the /shortcuts/inview.js using this method. Is it possible to use npm or bower to get access to these files?
Should be able to just add it to "main" I would think:
"dependencies": {
"jquery": "^3.3.1",
"waypoints": "^4.0.1"
},
"overrides" : {
"waypoints" : {
"main": [
"lib/jquery.waypoints.js",
"lib/shortcuts/sticky.js"
]
}
}

project.json scripts events can delete folders?

I am trying to delete a folder on post compile but cant make rd or del commands to work. Is there a way to delete a folder and subfolders from the scripts events?
Put the commands that you need in a batch or shell file and invoke that file in the post compile step
Use npm and gulp task, that not depends on the OS
Add a package.json file in your project root with gulp and gulp-rimraf dependencies:
{
"version": "1.0.0",
"description": "your description",
"name": "your project name",
"readme": "yuour readme",
"license": "Apache-2.0",
"dependencies": {
},
"devDependencies": {
"gulp": "3.9.1",
"gulp-rimraf": "0.2.0",
},
"scripts": {
"gulp": "gulp",
}
}
Add a gulpfile.js in your project root containing the cleanup task :
/// <binding Clean='clean' />
"use strict";
var gulp = require("gulp"),
rimraf = require("gulp-rimraf");
gulp.task("clean:js", function (cb) {
return rimraf("path to js folder to delete", cb);
});
gulp.task("clean:css", function (cb) {
return rimraf("path to css folder to delete", cb);
});
gulp.task("default", ["clean:js", "clean:css"]);
In your project.json, call the npm script :
{
...
"scripts": {
"precompile": "npm run gulp" // this will call the default gulp task
},
}
For more information, you can read the doc about how to use gulp on the asp.net docs site
You can do the same using grunt instead of gulp if you want

Gulp + Browserify + Jquery + Bootstrap

I'm trying to load jquery + jquery-ui + bootstrap inside my project throught NPM and gulp.
My configuration is this:
Package.json
"browser": {
"jquery": "/node_modules/jquery/dist/jquery.js",
"jquery-ui": "/node_modules/jquery-ui-browserify/jquery-ui.js"
},
"browserify-shim": {
"jquery": "$",
"jquery-ui": {
"exports": "jquery-ui",
"depends": [ "jquery:jQuery" ]
}
},
"browserify": {
"transform": [ "browserify-shim" ]
},
"dependencies": {
"bootstrap": "^3.3.6",
"jquery": "2.1.0",
"jquery-ui-browserify": "^1.11.0-pre-seelio",
}
gulpfile.js
gulp.task('browserify', function(){
return browserify([
'node_modules/jquery/dist/jquery.js',
'node_modules/jquery-ui-browserify/dist/jquery-ui.js',
'node_modules/bootstrap/dist/js/bootstrap.js',
])
.bundle()
.pipe(source('core.js'))
.pipe(buffer())
.pipe(gulp.dest('build/js'));
});
Then I load core.js with assetic from my index.php but I get this error:
Uncaught ReferenceError: jQuery is not defined
What am I doing wrong?
Thank you.
I don't know what you're trying to do there but keep in mind that what you should pass to the browserify instance is the entry point of your application, not your dependencies.
Then in your application you can use the require function to load those dependencies:
var $ = require('jquery');
While compiling browserify will autonomously do two things for you:
He will put into your bundle any library you required.
He will resolve your require statements by replacing them with a reference to the bundled copy of that library.
As long as the library is installed through npm you don't need any additional configuration. On the other hand if the library is situated in an unconventional location you'll need to tell browserify how to resolve it.
Anyway you can find more documentation on the repo's readme