Angular Router example Best way to upgrade to include .angular-cli.json and bypass Cannot read property 'config' of null - angular2-routing

I tried downloading the Routing and Navigation example from this page
Here's the link to the specific zip.
I run the following sequence of commands:
npm install
npm install --save-dev #angular/cli#latest
ng -v
ng serve -o
From what I can make out Cannot read property 'config' of null
is somehow related to a bad version of the CLI. But if I create a new project I can start it successfully with my existing setup
ng new router
cd router
npm install
ng serve -o
Old directory structure (from zip download) includes these files:
bs-config.json
e2e-spec.ts
New directory structure (from ng new):
.angular-cli.json
e2e is a folder with files inside
karma.conf.js
protractor.conf.js
tsconfig.json
Is there some sort of ng upgrade command to convert a project?
There was some talk on Git about ng init, but that seems to now be a thing of the past.
I believe most of the files are related to end to end testing.
npm install
npm WARN deprecated minimatch#0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
npm WARN deprecated node-uuid#1.4.8: Use uuid module instead
> phantomjs-prebuilt#2.1.14 install /opt/AngularProjects/router/node_modules/phantomjs-prebuilt
> node install.js
PhantomJS not found on PATH
Download already available at /var/folders/xz/sgpc803n1ms6xpc5n571ytc80000gn/T/phantomjs/phantomjs-2.1.1-macosx.zip
Verified checksum of previously downloaded file
Extracting zip contents
Removing /opt/AngularProjects/router/node_modules/phantomjs-prebuilt/lib/phantom
Copying extracted folder /var/folders/xz/sgpc803n1ms6xpc5n571ytc80000gn/T/phantomjs/phantomjs-2.1.1-macosx.zip-extract-1498561599287/phantomjs-2.1.1-macosx -> /opt/AngularProjects/router/node_modules/phantomjs-prebuilt/lib/phantom
Writing location.js file
Done. Phantomjs binary available at /opt/AngularProjects/router/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
> fsevents#1.1.2 install /opt/AngularProjects/router/node_modules/fsevents
> node install
[fsevents] Success: "/opt/AngularProjects/router/node_modules/fsevents/lib/binding/Release/node-v57-darwin-x64/fse.node" already installed
Pass --update-binary to reinstall or --build-from-source to recompile
npm notice created a lockfile as package-lock.json. You should commit this file.
added 767 packages in 20.239s
ng serve -o
Unable to find "#angular/cli" in devDependencies.
Please take the following steps to avoid issues:
"npm install --save-dev #angular/cli#latest"
You have to be inside an Angular CLI project in order to use the serve command.
/opt/AngularProjects/router>
npm install --save-dev #angular/cli#latest
npm WARN prefer global node-gyp#3.6.2 should be installed with -g
> node-sass#4.5.3 install /opt/AngularProjects/router/node_modules/node-sass
> node scripts/install.js
Cached binary found at /Users/jgf/.npm/node-sass/4.5.3/darwin-x64-57_binding.node
> node-sass#4.5.3 postinstall /opt/AngularProjects/router/node_modules/node-sass
> node scripts/build.js
Binary found at /opt/AngularProjects/router/node_modules/node-sass/vendor/darwin-x64-57/binding.node
Testing binary
Binary is fine
+ #angular/cli#1.1.3
added 431 packages in 17.132s
==
ng -v
_ _ ____ _ ___
/ \ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _|
/ △ \ | '_ \ / _` | | | | |/ _` | '__| | | | | | |
/ ___ \| | | | (_| | |_| | | (_| | | | |___| |___ | |
/_/ \_\_| |_|\__, |\__,_|_|\__,_|_| \____|_____|___|
|___/
#angular/cli: 1.1.3
node: 8.1.2
os: darwin x64
#angular/animations: 4.2.4
#angular/common: 4.2.4
#angular/compiler: 4.2.4
#angular/compiler-cli: 4.2.4
#angular/core: 4.2.4
#angular/forms: 4.2.4
#angular/http: 4.2.4
#angular/platform-browser: 4.2.4
#angular/platform-browser-dynamic: 4.2.4
#angular/platform-server: 4.2.4
#angular/router: 4.2.4
#angular/tsc-wrapped: 4.2.4
#angular/upgrade: 4.2.4
#angular/cli: 1.1.3
ng serve -o
Cannot read property 'config' of null
TypeError: Cannot read property 'config' of null
at Class.run (/opt/AngularProjects/router/node_modules/#angular/cli/tasks/serve.js:22:63)
at check_port_1.checkPort.then.port (/opt/AngularProjects/router/node_modules/#angular/cli/commands/serve.js:110:26)
at
at process._tickCallback (internal/process/next_tick.js:169:7)
In relation to the error in:
/opt/AngularProjects/router/node_modules/#angular/cli/tasks/serve.js
we have:
const config_1 = require("../models/config");
...
const projectConfig = config_1.CliConfig.fromProject().config;
I suspect this pertains to a missing .angular-cli.json file.
/opt/AngularProjects/router/node_modules/#angular/cli/models/config.d.ts
and
/opt/AngularProjects/router/node_modules/#angular/cli/models/config.js
refer to it.

That project (the one in the zip file) is not setup as a CLI-based project. But after opening it up, you can get it running by doing the following:
npm install
npm run start
This will open your default browser to http://localhost:3000/ where the app will be running.
NOTE: you'll also want to undo any changes you've made (or unzip again)

I converted the project to a CLI one, by following these steps, so I could run ng test and follow along with the Tour of Heroes project and run karma tests etc based on testing documentation:
Create a blank new project with ng new <project name>
Delete node_modules folder, then copied the following over into existing project:
.angular-cli.json
renaming "name:" key to same value of "name:" in package.json
e2e folder containing:
app.e2e-spec.ts
app.po.ts
tsconfig.e2e.json
karma.conf.js
protractor.conf.js
tsconfig.json (rename original to tsconfig.orig.json if necessary)
tslint.json (rename original to tsconfig.orig.json if necessary)
copy package.json to package.orig.json. Then in package.json...:
updated scripts: updating/adding:
"ng": "ng",
"build": "ng build",
"start": "ng serve",
"e2e": "ng e2e",
"test": "ng test",
"lint": "ng lint"
dependencies:
updated all #angular using modules
npm install #angular/<package-name>#latest --save
i.e.: (prefaced with #angular/) animations,common, compiler, core, forms, http, platform-browser, platform-browser-dynamic, router.
devDependencies:
npm install #angular/<package-name>#latest --save-dev
#angular/cli, #angular/compiler-cli, #angular/language-service
I also included in devDependencies:
"#types/jasmine": "2.5.45",
"#types/node": "~6.0.60",
"jasmine-core": "~2.6.2",
"jasmine-spec-reporter": "~4.1.0",
"karma": "^1.7.0",
"karma-chrome-launcher": "^2.1.1",
"karma-cli": "^1.0.1",
"karma-coverage-istanbul-reporter": "^1.2.1",
"karma-jasmine": "~1.1.0",
"karma-jasmine-html-reporter": "^0.2.2",
"protractor": "~5.1.2",
"ts-node": "~3.0.4",
"tslint": "^5.3.1",
"typescript": "~2.3.3"
In src folder copied:
assets/.gitkeep
environments/environment.prod.ts
environments/environment.ts
polyfills.ts
test.ts
tsconfig.app.json
tsconfig.spec.json
typings.d.ts
Replaced main.ts (In my case it added extra production env stuff)
In src folder:
renamed tsconfig.json tsconfig.orig.json (I was able to rely on tsconfig.app.json and tsconfig.spec.json)
You may need to tweak index.html. I did not..
run npm install
run ng serve -o
run ng test
Voila!
Note: If you get this error when running ng test:
Cannot read property 'length' of undefined
TypeError: Cannot read property 'length' of undefined
at createSourceFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:15457:109)
at parseSourceFileWorker (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:15389:26)
at Object.parseSourceFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:15338:26)
at Object.createSourceFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:15192:29)
at WebpackCompilerHost.getSourceFile (/opt/AngularProjects/quickstart/node_modules/#ngtools/webpack/src/compiler_host.js:210:27)
at findSourceFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:67909:29)
at processSourceFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:67840:27)
at processRootFile (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:67728:13)
at /opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:67018:60
at Object.forEach (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:1449:30)
at Object.createProgram (/opt/AngularProjects/quickstart/node_modules/typescript/lib/typescript.js:67018:16)
at AotPlugin._setupOptions (/opt/AngularProjects/quickstart/node_modules/#ngtools/webpack/src/plugin.js:129:28)
at new AotPlugin (/opt/AngularProjects/quickstart/node_modules/#ngtools/webpack/src/plugin.js:26:14)
at _createAotPlugin (/opt/AngularProjects/quickstart/node_modules/#angular/cli/models/webpack-configs/typescript.js:55:12)
at Object.exports.getNonAotTestConfig (/opt/AngularProjects/quickstart/node_modules/#angular/cli/models/webpack-configs/typescript.js:102:19)
at WebpackTestConfig.buildConfig (/opt/AngularProjects/quickstart/node_modules/#angular/cli/models/webpack-test-config.js:16:31)
it's because you've missed an required item. For me it was test.ts. See here.

Related

Husky prepare script failing firebase function deployment

I have installed husky in my npm project as a prepare script like below
{
"name": "functions",
"scripts": {
"build": "tsc",
"start": "npm run serve",
"deploy": "firebase deploy --only functions",
"prepare": "husky install functions/.husky"
}
"dependencies": {
"firebase-admin": "^11.4.1",
"firebase-functions": "^4.1.1",
},
"devDependencies": {
"husky": "^8.0.2",
"typescript": "^4.9.4"
}
}
husky is declared as devDependencies as this npm module is only required while local development and has no need in runtime app.
So when I run npm run deploy, I get the below error
i functions: updating Node.js 16 function funName(us-central1)...
Build failed:
> prepare
> husky install functions/.husky
sh: 1: husky: not found
npm ERR! code 127
npm ERR! path /workspace
npm ERR! command failed
npm ERR! command sh -c -- husky install functions/.husky
This error clearly states that husky is not installed.
One possible solution is to create a prepare.js script which checks if the script is running while in local development or in the firebase server(to prepare the project) and then conditionally run the husky npm module command
I just ran into this exact same issue but with tsc. I'm not sure why, but the prepare script is also run in the cloud function (not just locally) while deploying. However, considering you likely have the node_modules directory in the functions.ignore list in the firebase.json, the node_modules directory doesn't get uploaded as part of the deployment and so the husky package isn't visible to the script when it gets run in the cloud function environment.
You likely don't need the husky script to be run in the function environment either way, so you can add a condition to check for an environment variable that is usually set in the function environment (I am using the GOOGLE_FUNCTION_TARGET environment variable in my case), and only run the command if that environment is not set. You also need to wrap this in a bash script instead of adding it inline in the package.json because of how the prepare script is run.
For example, here's the content of my scripts/prepare.sh file.
#!/bin/bash
set -o verbose
# Only run if the GOOGLE_FUNCTION_TARGET is not set
if [[ -z "$GOOGLE_FUNCTION_TARGET" ]]; then
npm run build
fi
Then I use it in my package.json prepare script:
// ...
"prepare": "./scripts/prepare.sh",
// ...
There's potentially a better solution to this, but this is how I got it to work for me. Hope this helps!
This SO answer is spot on and uses bash script. I used the same concept mentioned in the answer to write the prepare script in js in scripts/ folder with the name of prepare.mjs
"use-strict";
import * as path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Firebase sets the GOOGLE_FUNCTION_TARGET when running in the firebase environment
const isFirebase = process.env.GOOGLE_FUNCTION_TARGET !== undefined;
if (!isFirebase) {
process.chdir("../"); // path where .git file is present. In my case it was ..
const husky = await import("husky");
husky.install("functions/.husky"); // path where .husjy config file is present w.r.t. .git file
}
And in my package.json I have used the above script as follows
{
"name": "functions",
"scripts": {
"build": "tsc",
"start": "npm run serve",
"deploy": "firebase deploy --only functions",
"prepare": "node ./scripts/prepare.mjs"
}
"dependencies": {
"firebase-admin": "^11.4.1",
"firebase-functions": "^4.1.1",
},
"devDependencies": {
"husky": "^8.0.2",
"typescript": "^4.9.4"
}
}
This uses the environment variable(GOOGLE_FUNCTION_TARGET) documented by the Google at the doc

How Can I bundle a simple node.js application

I am working with hyperledger-fabric on amazon managed blockchain. There I have written the chaincode with node.js. The problem is, the dependencies I'm using is not supported in amazon managed blockchain's peer. That's why I need to bundle my chaincode with the node modules. How can I do tha?
Here are steps for bundling Node.js chaincode with external dependencies on Amazon Managed Blockchain Hyperledger Fabric 2.2 networks:
Why bundling is needed:
Due to stringent security requirements, peer nodes in Amazon Managed Blockchain do not have access to the open internet. This means that peer nodes cannot download external dependencies at runtime when building/executing chaincode. If you suspect missing node_modules/ are responsible for errors in your chaincode, you can verify this by viewing Chaincode logs in Amazon CloudWatch, where reference to missing node_modules / dependencies will be clearly evident.
How to bundle dependencies
First, navigate to the root directory of the chaincode you wish to deploy. Your package.json file should be present in this directory. From this directory, run npm i to install node_modules. Then, move those node_modules to a new directory -- Example:
mv node_modules/ lib
Moving the dependencies to lib/ will allow you to package the installed NPM packages (dependencies) in the chaincode tar.gz file in the following steps. Because the node_modules are stored in lib/, the Node.js start script in package.json has been modified slightly to tell the container environment that runs the chaincode where to find the dependencies at runtime: "start": "NODE_PATH=lib node <entrypoint filename>.js"
{
"name": "chaincode",
"version": "1.0.0",
"scripts": {
"test": "NODE_PATH=lib mocha *_test.js",
"start": "NODE_PATH=lib node products.js"
},
"dependencies": {
"fabric-shim": "^2.0.0"
},
"devDependencies": {
"#theledger/fabric-mock-stub": "^2.0.3",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"chai-datetime": "^1.6.0",
"moment": "^2.25.3"
}
}
With the node_modules bundled in lib/ and the start script for the chaincode modified to point to those node_modules, one can now package, install, approve and commit this chaincode as normal using the Chaincode Lifecycle commands.

Create-React-App v2 with Node-SASS and CSS Modules works locally but crashes in Heroku

I'm using Create-React-App v2 and have installed node-sass. I also wish to use CSS Modules so I've changed the extensions and imports to .module.scss.
Note: I've imported the variables (_color.scss, _type.scss) into each component's stylesheet but it is not working so I've manually imported each needed variable to each component's stylesheet for now.
So now the app works locally but crashes in Heroku. Heroku logs states build failed and give 3 build output links for troubleshooting assistance. Here are the following build outputs.
1ST BUILD OUTPUT
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_ENV=production
NODE_MODULES_CACHE=true
NODE_VERBOSE=false
-----> Installing binaries
engines.node (package.json): unspecified
engines.npm (package.json): unspecified (use default)
Resolving node version 10.x...
Downloading and installing node 10.15.3...
Using default npm version: 6.4.1
-----> Restoring cache
- node_modules
-----> Installing dependencies
Installing node modules (package.json + package-lock)
audited 36784 packages in 17.665s
found 63 low severity vulnerabilities
run `npm audit fix` to fix them, or `npm audit` for details
-----> Build
Running build
> webportfolio#0.1.0 build /tmp/build_946ff21a3c8a665eda74215ba467f646
> react-scripts build
Creating an optimized production build...
Failed to compile.
./src/App.js
Cannot find file './Components/Portfolio/Portfolio' in './src'.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! webportfolio#0.1.0 build: `react-scripts build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the webportfolio#0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /tmp/npmcache.EQOTa/_logs/2019-03-11T23_54_27_075Z-debug.log
-----> Change to Node.js build process
Heroku has begun executing the "build" script defined in package.json
during Node.js builds.
Read more: https://devcenter.heroku.com/changelog-items/1573
-----> Build failed
We're sorry this build is failing! You can troubleshoot common issues here:
https://devcenter.heroku.com/articles/troubleshooting-node-deploys
Some possible problems:
- Node version not specified in package.json
https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version
Love,
Heroku
! Push rejected, failed to compile Node.js app.
! Push failed
2ND BUILD OUTPUT
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_ENV=production
NODE_MODULES_CACHE=true
NODE_VERBOSE=false
-----> Installing binaries
engines.node (package.json): unspecified
engines.npm (package.json): unspecified (use default)
Resolving node version 10.x...
Downloading and installing node 10.15.3...
Using default npm version: 6.4.1
-----> Restoring cache
- node_modules
-----> Installing dependencies
Installing node modules (package.json + package-lock)
audited 36784 packages in 17.814s
found 63 low severity vulnerabilities
run `npm audit fix` to fix them, or `npm audit` for details
-----> Build
Running build
> webportfolio#0.1.0 build /tmp/build_85b1987ab543478c5aee6f4728e8b330
> react-scripts build
Creating an optimized production build...
Failed to compile.
./src/App.js
Cannot find file './Components/Portfolio/Portfolio' in './src'.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! webportfolio#0.1.0 build: `react-scripts build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the webportfolio#0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /tmp/npmcache.htJgH/_logs/2019-03-12T00_00_58_185Z-debug.log
-----> Change to Node.js build process
Heroku has begun executing the "build" script defined in package.json
during Node.js builds.
Read more: https://devcenter.heroku.com/changelog-items/1573
-----> Build failed
We're sorry this build is failing! You can troubleshoot common issues here:
https://devcenter.heroku.com/articles/troubleshooting-node-deploys
Some possible problems:
- Node version not specified in package.json
https://devcenter.heroku.com/articles/nodejs-support#specifying-a-node-js-version
Love,
Heroku
! Push rejected, failed to compile Node.js app.
! Push failed
3RD BUILD OUTPUT
-----> Node.js app detected
-----> Creating runtime environment
NPM_CONFIG_LOGLEVEL=error
NODE_ENV=production
NODE_MODULES_CACHE=true
NODE_VERBOSE=false
-----> Installing binaries
engines.node (package.json): 10.5.0
engines.npm (package.json): unspecified (use default)
Resolving node version 10.5.0...
Downloading and installing node 10.5.0...
Using default npm version: 6.1.0
-----> Restoring cache
Cached directories were not restored due to a change in version of node, npm, yarn or stack
Module installation may take longer for this build
-----> Installing dependencies
Installing node modules (package.json + package-lock)
> node-sass#4.11.0 install /tmp/build_17cf925c197f17907d43d6369284d804/node_modules/node-sass
> node scripts/install.js
Downloading binary from https://github.com/sass/node-sass/releases/download/v4.11.0/linux-x64-64_binding.node
Download complete
Binary saved to /tmp/build_17cf925c197f17907d43d6369284d804/node_modules/node-sass/vendor/linux-x64-64/binding.node
Caching binary to /tmp/npmcache.Dfkzs/node-sass/4.11.0/linux-x64-64_binding.node
> node-sass#4.11.0 postinstall /tmp/build_17cf925c197f17907d43d6369284d804/node_modules/node-sass
> node scripts/build.js
Binary found at /tmp/build_17cf925c197f17907d43d6369284d804/node_modules/node-sass/vendor/linux-x64-64/binding.node
Testing binary
Binary is fine
added 1883 packages from 750 contributors and audited 36784 packages in 39.346s
found 63 low severity vulnerabilities
run `npm audit fix` to fix them, or `npm audit` for details
-----> Build
Running build
> webportfolio#0.1.0 build /tmp/build_17cf925c197f17907d43d6369284d804
> react-scripts build
Creating an optimized production build...
Failed to compile.
./src/App.js
Cannot find file './Components/Portfolio/Portfolio' in './src'.
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! webportfolio#0.1.0 build: `react-scripts build`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the webportfolio#0.1.0 build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /tmp/npmcache.Dfkzs/_logs/2019-03-12T01_08_21_381Z-debug.log
-----> Change to Node.js build process
Heroku has begun executing the "build" script defined in package.json
during Node.js builds.
Read more: https://devcenter.heroku.com/changelog-items/1573
-----> Build failed
We're sorry this build is failing! You can troubleshoot common issues here:
https://devcenter.heroku.com/articles/troubleshooting-node-deploys
If you're stuck, please submit a ticket so we can help:
https://help.heroku.com/
Love,
Heroku
! Push rejected, failed to compile Node.js app.
! Push failed
Solutions I've attempted:
https://devcenter.heroku.com/articles/troubleshooting-node-deploys#check-your-gitignore
uninstalling the global instance of npm, then reinstalled the latest recommended-for-most users version
npm rebuild node-sass
I've been stuck for awhile and would really appreciate any help. Thanks in advance!
Package installed
• Node.js v10.15.3 to /usr/local/bin/node
• npm v6.4.1 to /usr/local/bin/npm
Okay... this project needs a lot of stylesheet reworking.
All of your component level .scss files should be within the same folder as the component that requires it. Any partial files should be imported within the component-level scss that needs them. Some of your stylesheets are doing it, but some aren't. Also, for whatever reason, you're importing partials within a css stylesheet and importing partials within scss stylesheets. Just stick to scss stylesheets!
To summarize:
Any stylesheet that needs to be used by a component should be within the
same folder as the component.
Any stylesheet that needs to be used by many components, should be a partial file that is imported into a component-level stylesheet.
Right now you have partials, like _app_portfolio.scss files under Sass and component level Portfolio.module.scss stylesheets which are separately being required for Portfolio.js. This is an antipattern. Partials should be reusebale stylesheets that will imported into multiple component level stylesheets for re-usage.
For example, you should structure your app like so: (for simplicity, your main directory folders should be lowercase):
├── src
| ├── components
| | └── Portfolio
| | ├── Portfolio.js
| | └── Portfolio.scss (non-partial file, this component-level stylesheet contains all of styles required for Portfolio.js)
| |
| ├── images
| ├── styles
| | ├── base
| | | └── _base.scss (partial file, include any DOM-level styles like "a" or "p", or "div", "body", "html" ... etc.)
| | |
| | ├── exts
| | | └── _extensions.scss (partial file, include any extended styles like ".clear fix", which is a classname that'll contain repetitive style patterns)
| | |
| | ├── globals
| | | └── globals.scss (non-partial file, include any GLOBAL stylesheets, like "normalize.css", this stylesheet will be directly imported into ./src/index.js like so: import "./styles/globals/globals.scss";)
| | |
| | ├── mixins
| | | └── _mixins.scss (partial file, define your mixins that'll be shared with component-level scss)
| | |
| | ├── vars
| | | └── _vars.scss (partial file, define your variables that'll be shared with component-level scss)
| | |
| | └── index.scss (OPTIONAL non-partial file that imports all of the partial files above, then this file can be imported into a component-level stylesheet. Instead of writing 4 imports for base, exts, mixins and vars, you'll just do: #import '../path/to/styles/index.scss'; now you have included all 4 partials within 1 import)
| |
| └── index.js
How to implement the above...
components/Portfolio/Portfolio.js
import React from "react";
import Profile from "../Profile/Profile";
import { portfolioContainer } from "./Portfolio.scss"; // import the className, if there are many classes, then just import them as "styles" from './stylesheet.scss'; then use: "styles.portfolioContainer", "styles.example", "styles.example2" ...etc
const Portfolio = () => {
return (
<div className={portfolioContainer}>
<Profile />
</div>
);
};
export default Portfolio;
components/Portfolio/Portfolio.scss
#import '../../styles/vars/vars.scss'; // partial file import, now we can use $variables
#import '../../styles/mixins/mixins.scss'; // partial file import, now we can use #include mixinname();
#import '../../styles/exts/extensions.scss'; // partial file import, now we can use #extend .classname;
.portfolioContainer {
#include grid-template-columns(1);
color: $brightgreen;
background: url('../../images/example.png'); // include your image imports within the component-level stylesheet -- if you import it in a partial file, then import that partial within a stylesheet, then you'll run into some pathing issues. The path defined will be relative to the partial and won't be an absolute path to the image when imported within the component-level stylesheet.
display: flex;
flex-flow: column wrap;
height: 100vh;
&::after {
#extend .clear-fix;
}
}
Take a look at this Sass Basics Guide.
If you're having a hard time understanding, please see my react-starter-kit, which includes notes within styles/index.scss and styles/globals/globals.scss and how to utilize partials in components/Home/Home.scss and be imported into components/Home/Home.js and how to utilize globals in src/index.js.
Since you're using the create-react-app, you may need a sass-compiler to compile the .scss files to one or many .css files. Unfortunately, I don't use the CRA, so you'll have to dive into the docs to find out how.

How to prevent yarn install from running twice in Makefile?

I have this in my Makefile:
node_modules: yarn.lock
yarn install --production=false
touch node_modules
yarn.lock: package.json
yarn install --production=false
touch yarn.lock
Basically, if the node_modules directory is missing (or someone has tampered with it by adding/removing files), or yarn.lock has been updated, then it should run yarn install to rebuild/integrity check the node_modules dir.
However, if yarn.lock is missing, it can be rebuilt from package.json, or if package.json is updated, then it should install and rebuild the lock file.
The problem is when both node_modules and yarn.lock are missing, then the same commands run twice.
How can I prevent this?
I can nearly get it to work by wrapping the directives in a conditional:
ifneq ("$(wildcard yarn.lock)","")
node_modules: yarn.lock
#yarn install --production=false
touch node_modules
yarn.lock: package.json
touch yarn.lock
else # yarn.lock does not exist
node_modules: yarn.lock
touch node_modules
yarn.lock: package.json
#yarn install --production=false
endif
Now if you touch package.json and then make node_modules and yarn.lock exists, then it'll subsequently touch yarn.lock which will cause node_modules to rebuild, just like I want.
However, if you touch package.json and then make yarn.lock, technically it should attempt a yarn install but it won't because I removed the command from this directive:
yarn.lock: package.json
touch yarn.lock
To prevent it from running twice in the former scenario.
To a first approximation, consider the approach illustrated here:
Makefile (1)
.PHONY: all clean
all: yarn.lock
yarn.lock: node_modules package.json
$(MAKE clean)
yarn install --production=false
node_modules:
mkdir -p $#
clean:
rm -fr node_modules yarn.lock
This will never run yarn install redundantly, and it's a somewhat more
robust solution than you're considering. I'll explain.
The one source item in the problem is the package.json. It is the sole
logical prerequisite of everything else and is not itself to be built.
The yarn.lock is a build-artefact whose production signifies that that
yarn install has been done successfully with respect to the snapshot
of package.json that existed when it was done. yarn install will
subsequently consider that the installation is up-to-date as long as yarn.lock
exists and has contents that "agree" with package.json by criteria
that are algorithmically embodied in yarn install.
So, viewed simplistically, the mission of this build is just to make yarn.lock
up-to-date with respect to package.json:
yarn.lock: package.json
yarn install --production=false
But it's actually more complicated. yarn.lock is the build target but
it isn't the only build-artefact and it isn't even one of the artefacts of
primary value. Those, of course, are whatever artefacts will populate
node-modules as a result of running yarn install.
So the primary build-artefacts appear as side effects of this build,
while the actual target, yarn.lock matters to us only as a token that
the primary artefacts, whatever they may be, have been made up-to-date
with the package.json.
And it is a frail token. Agencies can mess with the contents of
node_modules - adding files that shouldn't be there, deleting or
modifying ones that should - and yarn install won't do anything to
rectify it as long as it considers yarn.lock up-to-date with package.json,
by its own criteria.
You adverted to that fragility in explaining the suggested recipe:
node_modules: yarn.lock
yarn install --production=false
touch node_modules
if the node_modules directory is missing (or someone has tampered with it by
adding/removing files), or yarn.lock has been updated, then it should run yarn
install to rebuild/integrity check the node_modules dir.
But that rule is the wrong way round to be triggered by such tampering. The
tampering - if you're lucky - will update the modification time of node_modules.
But that will make it younger, not older, than yarn.lock, and won't fire
the recipe. The recipe is only good for the case in which node_modules does not exist.
That weakness is mitigated by the recipe:
yarn.lock: node_modules package.json
$(MAKE) clean
yarn install --production=false
If yarn.lock doesn't exist, or is out-of-date w.r.t to either node_modules
or package_json, we'll remake all the build-artefacts from scratch.
That's better, but brings with it a boot-strap problem, when neither of the
artefacts yarn.lock or node_modules exists but node_modules - which is to
be populated as a by product of making yarn.lock - is also a perquisite of yarn.lock.
It's a trivial problem however. The prerequisite for yarn.lock is the mere existence
of node_modules and it is satisfiable prior to making yarn.lock, and the
contents of node_modules, up-to-date - by just adding the recipe:
node_modules:
mkdir -p $#
With this, if node_modules ever doesn't exist, it will be created as
a prerequisite of yarn.lock, making it newer than yarn.lock, and requiring
yarn.lock and the primary build-artefacts to be made.
But...
This solution expresses the dependency relations essentially right and - as
a consequence - shows how yarn install never needs to be run redundantly. And
it corrects the wrong-way-round bug in your tamper-detection logic.
But is still falls short of strong tamper-detection.
The tamper-detection mechanism we've got is: Something happens in the node_modules
directory that makes its modification date later than that of yarn.lock. That
will detect some tampering, but not all tampering.
As a filesystem object, a directory is modified - and its modification time updated
- if and only if an immediate child object is added, removed, or renamed. So
the tamper-detection mechanism is blind to all events inside any subdirectory of
node_modules and to any modification of an existing file or subdirectory of
node_modules except renaming it. That leaves ample scope for messing up
the node_modules.
In that light, you might decide to:-
Stick
Flimsy tamper-detection is better than none. I don't want to use any
more expensive than this.
But you probably wouldn't. More likely alternatives:
Fold
Tamper-detection this flimsy is no better than none, so I'll fall back to:
yarn.lock: package.json
yarn install --production=false
I'll regard improper tampering as out-of-scope for my build. If it happens, something will break,
I'll notice it, make clean and try again.
Up the ante
I want strong tamper-detection.
Strong tamper-detection makes rather heavier lifting - but not much heavier.
You need to force a clean yarn install, or not, depending on the outcome of an
old-versus-new comparison between complete manifests of the contents of node_modules -
manifests informative enough that any material difference will show up.
A manifest detailing the pathname and modification time of every file in
node_modules is the best candidate. This manifest will contain the information that make
would need to know, and would get from the file system, if the elusive primary artefacts
of this build could be spelled out to it, and a change in that information relative to
its last recorded state is a reliable trigger to remake everything. Thus:
Makefile (2)
RM := rm -fr
MANIFEST_DIR := .manifest
LAST_MANIFEST := $(MANIFEST_DIR)/node_modules.last
NEW_MANIFEST := $(MANIFEST_DIR)/node_modules.peek
GEN_MANIFEST := find node_modules/ -exec stat -c '%n %y' {} \;
$(shell mkdir -p $(MANIFEST_DIR) node_modules)
$(if $(wildcard $(LAST_MANIFEST)),,$(shell touch $(LAST_MANIFEST)))
$(shell $(GEN_MANIFEST) > $(NEW_MANIFEST))
$(shell cmp -s $(LAST_MANIFEST) $(NEW_MANIFEST) || touch node_modules)
.PHONY: all clean
all: $(LAST_MANIFEST)
yarn.lock: node_modules package.json
$(RM) yarn.lock node_modules
yarn install --production=false
$(LAST_MANIFEST): yarn.lock
$(GEN_MANIFEST) > $#
clean:
$(RM) yarn.lock node_modules $(MANIFEST_DIR)
This develops Makefile (1) mainly with the unconditionally executed apparatus
at the top, which:-
Ensures (as before) we start with a node_modules directory, even if empty.
Ensures we start with a hidden directory (.manifest) for working in
and for persisting the latest manifest of node_modules. (Analogous to
the hidden .deps directory classically used for persisting autodependency files
in C/C++ makes).
Ensures we start with a persisted manifest, even if empty.
Generates a new, true, manifest snapshot with: find node_modules/ -exec stat -c '%n %y' {} \;,
which writes <filename> <modification_time> for each item under node_modules.
This snapshot is true of node_modules as it is, but not necessarily true
of node_modules as it should be. (Should it follow symlinks? - find -L ...?
No. Because make wouldn't follow symlinks for targets or prerequisites).
Compares the new, true, snapshot with the persisted manifest and, if
there is any difference, then touches node_modules.
This amounts to a build preamble that will update the modification
time of node_modules, or not, by a strong tamper-detecting test. Then
the build is much as before except that its target is no longer
yarn.lock, but a new persisted manifest, $(LAST_MANIFEST), that is always an
immediate post-yarn-install snapshot and accordingly dependent on
yarn.lock.
A workout for Makefile (2)
For a lab-rat package.json
I'll use:
{
"name": "node-js-sample",
"version": "0.2.0",
"description": "A sample Node.js app using Express 4",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.13.3"
},
"engines": {
"node": "4.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/heroku/node-js-sample"
},
"keywords": [
"node",
"heroku",
"express"
],
"author": "Mark Pundsack",
"contributors": [
"Zeke Sikelianos <zeke#sikelianos.com> (http://zeke.sikelianos.com)"
],
"license": "MIT"
}
Make from scratch
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.17s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Change nothing and remake
$ make
make: Nothing to be done for 'all'.
Touch node_modules only
$ touch node_modules/
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.01s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Touch package.json only
$ touch package.json
imk#imk-ThinkPad-T420:~/develop/so/make_prob$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.22s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Touch node_modules and package.json
$ touch package.json node_modules/
imk#imk-ThinkPad-T420:~/develop/so/make_prob$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.05s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Touch yarn.lock
$ touch yarn.lock
$ make
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Delete yarn.lock
$ rm yarn.lock
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.17s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Change a dependency in package.json
$ sed -i 's/4\.13\.3/4.15.3/' package.json
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.03s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Undo the change
$ sed -i 's/4\.15\.3/4.15.3/' package.json
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 2.35s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Touch an existing file in a subdirectory of node_modules
$ ls node_modules/vary/
HISTORY.md index.js LICENSE package.json README.md
$ touch node_modules/vary/README.md
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.02s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Add a file to a subdirectory of node_modules
$ touch node_modules/vary/interloper
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.20s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Remove a file from a subdirectory of node_modules
$ rm node_modules/vary/README.md
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.16s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
Borrowing from Mike, I think this is robust enough for my needs:
BIN := node_modules/.bin
SRC_FILES := $(shell find src -name '*.js')
DIST_FILES := $(patsubst src/%,dist/%,$(SRC_FILES))
DIST_DIRS := $(sort $(dir $(DIST_FILES)))
# these are not files
.PHONY: all clean nuke
# disable default suffixes
.SUFFIXES:
all: $(DIST_FILES)
dist/%.js: src/%.js yarn.lock .babelrc | $(DIST_DIRS)
$(BIN)/babel $< -o $#
$(DIST_DIRS):
mkdir -p $#
yarn.lock: node_modules package.json
#yarn install --production=false --check-files
#touch -mr $(shell ls -Atd $? | head -1) $#
node_modules:
mkdir -p $#
clean:
rm -rf node_modules dist
nuke: clean
rm -rf yarn.lock
I added
#touch -mr $(shell ls -Atd $? | head -1) $#
Which updates the modification time of yarn.lock to the newer of node_modules or package.json. This is necessary for when those are touched but don't result in a lockfile change -- yarn install won't update the file which will cause yarn.lock to be perpetually out of date.
--check-files will force yarn install to actually reinstall any missing packages inside node_modules/, but it won't do a deep search. So if tamper some files inside of a package (rather than just deleting the whole package), this sort of change won't be caught.
The babel stuff is just an example of how I'm using this. It will recompile only the source files that have changed. Now I just have to run make in a freshly cloned project and it will bring everything up to date with one command.

How to compile or convert sass / scss to css with node-sass (no Ruby)?

I was struggling with setting up libsass as it wasn't as straight-forward as the Ruby based transpiler. Could someone explain how to:
install libsass?
use it from command line?
use it with task runners like gulp and grunt?
I have little experience with package managers and even less so with task runners.
I picked node-sass implementer for libsass because it is based on node.js.
Installing node-sass
(Prerequisite) If you don't have npm, install Node.js first.
$ npm install -g node-sass installs node-sass globally -g.
This will hopefully install all you need, if not read libsass at the bottom.
How to use node-sass from Command line and npm scripts
General format:
$ node-sass [options] <input.scss> [output.css]
$ cat <input.scss> | node-sass > output.css
Examples:
$ node-sass my-styles.scss my-styles.css compiles a single file manually.
$ node-sass my-sass-folder/ -o my-css-folder/ compiles all the files in a folder manually.
$ node-sass -w sass/ -o css/ compiles all the files in a folder automatically whenever the source file(s) are modified. -w adds a watch for changes to the file(s).
More usefull options like 'compression' # here. Command line is good for a quick solution, however, you can use task runners like Grunt.js or Gulp.js to automate the build process.
You can also add the above examples to npm scripts. To properly use npm scripts as an alternative to gulp read this comprehensive article # css-tricks.com especially read about grouping tasks.
If there is no package.json file in your project directory running $ npm init will create one. Use it with -y to skip the questions.
Add "sass": "node-sass -w sass/ -o css/" to scripts in package.json file. It should look something like this:
"scripts": {
"test" : "bla bla bla",
"sass": "node-sass -w sass/ -o css/"
}
$ npm run sass will compile your files.
How to use with gulp
$ npm install -g gulp installs Gulp globally.
If there is no package.json file in your project directory running $ npm init will create one. Use it with -y to skip the questions.
$ npm install --save-dev gulp installs Gulp locally. --save-dev adds gulp to devDependencies in package.json.
$ npm install gulp-sass --save-dev installs gulp-sass locally.
Setup gulp for your project by creating a gulpfile.js file in your project root folder with this content:
'use strict';
var gulp = require('gulp');
A basic example to transpile
Add this code to your gulpfile.js:
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('sass', function () {
gulp.src('./sass/**/*.scss')
.pipe(sass().on('error', sass.logError))
.pipe(gulp.dest('./css'));
});
$ gulp sass runs the above task which compiles .scss file(s) in the sass folder and generates .css file(s) in the css folder.
To make life easier, let's add a watch so we don't have to compile it manually. Add this code to your gulpfile.js:
gulp.task('sass:watch', function () {
gulp.watch('./sass/**/*.scss', ['sass']);
});
All is set now! Just run the watch task:
$ gulp sass:watch
How to use with Node.js
As the name of node-sass implies, you can write your own node.js scripts for transpiling. If you are curious, check out node-sass project page.
What about libsass?
Libsass is a library that needs to be built by an implementer such as sassC or in our case node-sass. Node-sass contains a built version of libsass which it uses by default. If the build file doesn't work on your machine, it tries to build libsass for your machine. This process requires Python 2.7.x (3.x doesn't work as of today). In addition:
LibSass requires GCC 4.6+ or Clang/LLVM. If your OS is older, this version may not compile. On Windows, you need MinGW with GCC 4.6+ or VS 2013 Update 4+. It is also possible to build LibSass with Clang/LLVM on Windows.
The installation of these tools may vary on different OS.
Under Windows, node-sass currently supports VS2015 by default, if you only have VS2013 in your box and meet any error while running the command, you can define the version of VS by adding: --msvs_version=2013. This is noted on the node-sass npm page.
So, the safe command line that works on Windows with VS2013 is:
npm install --msvs_version=2013 gulp node-sass gulp-sass
npx node-sass input.scss out.css
In Windows 10 using node v6.11.2 and npm v3.10.10, in order to execute directly in any folder:
> node-sass [options] <input.scss> [output.css]
I only followed the instructions in node-sass Github:
Add node-gyp prerequisites by running as Admin in a Powershell (it takes a while):
> npm install --global --production windows-build-tools
In a normal command-line shell (Win+R+cmd+Enter) run:
> npm install -g node-gyp
> npm install -g node-sass
The -g places these packages under %userprofile%\AppData\Roaming\npm\node_modules. You may check that npm\node_modules\node-sass\bin\node-sass now exists.
Check if your local account (not the System) PATH environment variable contains:
%userprofile%\AppData\Roaming\npm
If this path is not present, npm and node may still run, but the modules bin files will not!
Close the previous shell and reopen a new one and run either > node-gyp or > node-sass.
Note:
The windows-build-tools may not be necessary (if no compiling is done? I'd like to read if someone made it without installing these tools), but it did add to the admin account the GYP_MSVS_VERSION environment variable with 2015 as a value.
I am also able to run directly other modules with bin files, such as > uglifyjs main.js main.min.js and > mocha

Resources