Variables in .env is empty when deploy to production using ZEIT Now - production-environment

I have built a project from scratch using React and deploy it to ZEIT. In development mode, all variables in .env file are loaded(using dotenv-webpack) and everything works perfect.
By default, ZEIT Now will ignore .env in production so I put all my .env variables to now.json like this
{ "version": 2, "alias": "goccuathi", "regions": [ "sin1" ], "build": { "env": { "OWNER_EMAIL": "#gct_owner-email", "TINYMCE_KEY": "#gct_tinymce-key", "GA_ID": "#gct_ga-key" } }, "env": { "OWNER_EMAIL": "#gct_owner-email", "TINYMCE_KEY": "#gct_tinymce-key", "GA_ID": "#gct_ga-key" } }
And here is logs:
{"id":"dpl_2wDwTfqRGa46WYsCeSh31zmsHnke","lambdas":[{"id":"bld_pw942tu0q","createdAt":1585988984285,"entrypoint":"package.json","readyState":"INITIALIZING","readyStateAt":1585988984285,"output":[]}],"public":false,"readyState":"QUEUED","regions":["sin1"],"url":"goccuathi-9mtrc5d9i.now.sh","version":2,"build":{"env":["OWNER_EMAIL","TINYMCE_KEY","GA_ID"]},"builds":[{"src":"package.json","use":"#now/static-build","config":{"zeroConfig":true}}],"createdAt":1585988983745,"createdIn":"sfo1","env":[],"meta":{},"name":"goccuathi","ownerId":"cYIfFUzo4cG4SkSwFNEEOLE5","plan":"hobby","routes":[],"target":"production","functions":null,"projectId":"QmcrHSmFE6x35GgZuxnkkQfJdjW3K5RjKG1yNL4EBrxgjm","type":"LAMBDAS","team":null,"creator":{"uid":"cYIfFUzo4cG4SkSwFNEEOLE5","username":"anhthi-ieig"},"bootedAt":1585988983745,"buildingAt":1585988983745,"status":"QUEUED","alias":["goccuathi.now.sh","goccuathi.anhthi-ieig.now.sh"],"aliasAssigned":false}
My .env variables in production are empty.
What am I doing wrong?

Related

How do I access .env variables and use it inside the cypress.json file?

I have five different cypress projects in the same repo.
The Cypress.json file of each project has reporterOptions :
{
"fixturesFolder": "./src/fixtures",
"integrationFolder": "./src/integration",
……..
"reporter": "../../node_modules/mocha-testrail-reporter",
"reporterOptions": {
"username": "my-user-name”,
"password": "my-password",
"host": "https://abc.testrail.io",
"domain": "abc.testrail.io",
"projectId": 1,
"suiteId": 3,
"includeAllInTestRun": true,
"runName": "test"
}
}
The Username, host, password and domain value are same for all five cypress projects. Thus, I want to put them in the .env file like this, and access these variables and use them in the Cypress.json files
USERNAME= my-user-name
PASSWORD= my-password
HOST= https://abc.testrail.io
DOMAIN= abc.testrail.io
How do I access these variables? Any help will be appreciated. Thank you,
Take a look at Extending the Cypress Config File
Cypress does not support extends syntax in its configuration file
But in plugins it can be done
module.exports = (on, config) => {
const reporterParams = require('.env') // not quite sure of the format
// may need to fiddle it
const reportOptions = {
...config.reporterOptions, // spread existing options
"username": reporterParams.username,
"password": reporterParams.password,
"host": reporterParams.host,
"domain": reporterParams.domain,
}
const merged = {
...config,
reportOptions
}
return merged
}

How to deploy Next.js with GraphQL backend on Zeit Now?

I have an Next.js/Express/Apollo GraphQL app running fine on localhost.
I try to deploy it on Zeit Now, and the Next.js part works fine, but the GraphQL backend fails because /graphql route returns:
502: An error occurred with your deployment
Code: NO_STATUS_CODE_FROM_LAMBDA
My now.json looks like:
{
"version": 2,
"builds": [
{ "src": "next.config.js", "use": "#now/next" },
{ "src": "server/server.js", "use": "#now/node" }
],
"routes": [
{ "src": "/api/(.*)", "dest": "server/server.js" },
{ "src": "/graphql", "dest": "server/server.js" }
]
}
Suggestions?
Here’s a complete example of Next.js/Apollo GraphQL running both on Zeit Now (as serverless function/lambda) and Heroku (with an Express server):
https://github.com/tomsoderlund/nextjs-pwa-graphql-sql-boilerplate
I was getting that error until I found on a solution on the Wes Bos slack channel.
The following worked for me, but it's possible you could be getting that error for a different reason.
I'm not sure why it works.
You can see it working here
cd backend
Run npm install graphql-import
Update scripts in package.json:
"deploy": "prisma deploy --env-file variables.env&& npm run writeSchema",
"writeSchema": "node src/writeSchema.js"
Note: For non windows users make sure to place space before &&
Create src/writeSchema.js:
const fs = require('fs');
const { importSchema } = require('graphql-import');
const text = importSchema("src/generated/prisma.graphql");
fs.writeFileSync("src/schema_prep.graphql", text)
Update src/db.js:
const db = new Prisma({
typeDefs: __dirname + "/schema_prep.graphql",
...
});
Update src/createServer.js:
return new GraphQLServer({
typeDefs: __dirname + '/schema.graphql',
...
});
Update src/schema.graphql:
# import * from './schema_prep.graphql'
Create now.json
{
"version": 2,
"name": "Project Name",
"builds": [
{ "src": "src/index.js", "use": "#now/node-server" }
],
"routes": [
{ "src": "/.*", "dest": "src/index.js" }
],
"env": {
"SOME_VARIABLE": "xxx",
...
}
}
Run npm run deploy to initially create schema_prep.graphql.
Run now
Another reply said this:
You should not mix graphql imports and js/ts imports. The syntax on the graphql file will be interpreted by graphql-import and will be ignored by ncc (the compiler which reads the __dirname stuff and move the file to the correct directory etc)
In my example 'schema_prep.graphql' is already preprocessed with the imports from the generated graphql file.
Hopefully this helps.

How to deploy SCSS file to dist in angular 6?

We have a need to deploy scss files to dist directory when angular is building. I am fully aware that only css should be deployed after the build however we have custom need to read the scss file on run time and perform certain action.
I tried adding below line (last line under scripts:) in angular.json file but that did not help. I cant find any file deploying during debug.
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"src/scss/styles.scss"
],
"scripts": [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.js",
"src/scss/_custom-variables.scss"
]
},
"assets": [
"src/favicon.ico",
"src/assets",
"src/scss/_custom.scss"
],
Adding this under assets in angular.json file works for me. I was looking under wrong folder.
Out of the box; angular 6 does not provide a way to do this natively. However; you can achieve what you are describing by using custom webpack configuration that utilizes Angular 6 builders.
For example, you can use Custom Webpack Builder. Due to the nature of builders,their configuration is merged with CLI own configuration, so all you need to do is to create a minimalistic configuration utilizing Webpack Copy Plugin; then use glob patterns to catch & copy all required .scss files to dist/ directory.
You can try to fiddle with similar webpack configuration:
"use strict";
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyWebpackPlugin([
{
from: "src/app/**/*.scss",
to: "dist/app/"
}
]
)
]
};
Alternatively; if you do not require ejected SCSS during development and only in production package, you can use simple Gulp task to copy the files
"use strict";
let gulp = require("gulp");
gulp.task("copy:styles", () =>
gulp.src(["src/app/**/*.scss"])
.pipe(gulp.dest("dist/app/")));

Use enviroment variables in yarn package.json

I want to pull from a private package hosted on bitbucket. Since SSH is not an option for my deploy setup, I want to access the repo using the Application Password.
So my entry in the package JSON looks like this:
"dependencies": {
"#companyName/repository": "git+https://${$BITBUCKET_USER}:${BITBUCKET_APP_PASSWORD}#bitbucket.org/company name/repository.git",
Coding username and password hard into the repo URL works fine but when I perform yarn install as above, the environment variables are not replaced by its values.
Is there any way to use environment variables like this?
You can write a preinstall hook that updates package.json with values from the environment. Luckily the order of lifecycle hooks work as prescribed using yarn.
{
"name": "njs",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"preinstall": "node preinstall.js"
},
"dependencies": {
"#companyName/repository": "git+https://${$BITBUCKET_USER}:${BITBUCKET_APP_PASSWORD}#bitbucket.org/companyName/repository.git"
},
"author": "",
"license": "ISC"
}
preinstall.js example:
const package = require('./package.json');
const fs = require('fs');
const {BITBUCKET_USER = 'test', BITBUCKET_APP_PASSWORD='test'} = process.env;
package.dependencies["#companyName/repository"] = package.dependencies["#companyName/repository"]
.replace("${$BITBUCKET_USER}", BITBUCKET_USER)
.replace("${BITBUCKET_APP_PASSWORD}", BITBUCKET_APP_PASSWORD);
fs.writeFileSync('package.json', JSON.stringify(package, null, 4));
Bonus:
How you choose to replace environment variables in preinstall.js is left to your good judgment. Yes, you can totally use ES6 template tags.

How do I use CloudFormation resources in a Lambda function?

I have added a Redis ElastiCache section to my s-resource-cf.json (a CloudFormation template), and selected its hostname as an output.
"Resources": {
...snip...
"Redis": {
"Type": "AWS::ElastiCache::CacheCluster",
"Properties": {
"AutoMinorVersionUpgrade": "true",
"AZMode": "single-az",
"CacheNodeType": "cache.t2.micro",
"Engine": "redis",
"EngineVersion": "2.8.24",
"NumCacheNodes": "1",
"PreferredAvailabilityZone": "eu-west-1a",
"PreferredMaintenanceWindow": "tue:00:30-tue:01:30",
"CacheSubnetGroupName": {
"Ref": "cachesubnetdefault"
},
"VpcSecurityGroupIds": [
{
"Fn::GetAtt": [
"sgdefault",
"GroupId"
]
}
]
}
}
},
"Outputs": {
"IamRoleArnLambda": {
"Description": "ARN of the lambda IAM role",
"Value": {
"Fn::GetAtt": [
"IamRoleLambda",
"Arn"
]
}
},
"RedisEndpointAddress": {
"Description": "Redis server host",
"Value": {
"Fn::GetAtt": [
"Redis",
"Address"
]
}
}
}
I can get CloudFormation to output the Redis server host when running sls resources deploy, but how can I access that output from within a Lambda function?
There is nothing in this starter project template that refers to that IamRoleArnLambda, which came with the example project. According to the docs, templates are only usable for project configuration, they are not accessible from Lambda functions:
Templates & Variables are for Configuration Only
Templates and variables are used for configuration of the project only. This information is not usable in your lambda functions. To set variables which can be used by your lambda functions, use environment variables.
So, then how do I set an environment variable to the hostname of the ElastiCache server after it has been created?
You can set environment variables in the environment section of a function's s-function.json file. Furthermore, if you want to prevent those variables from being put into version control (for example, if your code will be posted to a public GitHub repo), you can put them in the appropriate files in your _meta/variables directory and then reference those from your s-function.json files. Just make sure you add a _meta line to your .gitignore file.
For example, in my latest project I needed to connect to a Redis Cloud server, but didn't want to commit the connection details to version control. I put variables into my _meta/variables/s-variables-[stage]-[region].json file, like so:
{
"redisUrl": "...",
"redisPort": "...",
"redisPass": "..."
}
…and referenced the connection settings variables in that function's s-function.json file:
"environment": {
"REDIS_URL": "${redisUrl}",
"REDIS_PORT": "${redisPort}",
"REDIS_PASS": "${redisPass}"
}
I then put this redis.js file in my functions/lib directory:
module.exports = () => {
const redis = require('redis')
const jsonify = require('redis-jsonify')
const redisOptions = {
host: process.env.REDIS_URL,
port: process.env.REDIS_PORT,
password: process.env.REDIS_PASS
}
return jsonify(redis.createClient(redisOptions))
}
Then, in any function that needed to connect to that Redis database, I imported redis.js:
redis = require('../lib/redis')()
(For more details on my Serverless/Redis setup and some of the challenges I faced in getting it to work, see this question I posted yesterday.)
update
CloudFormation usage has been streamlined somewhat since that comment was posted in the issue tracker. I have submitted a documentation update to http://docs.serverless.com/docs/templates-variables, and posted a shortened version of my configuration in a gist.
It is possible to refer to a CloudFormation output in a s-function.json Lambda configuration file, in order to make those outputs available as environment variables.
s-resource-cf.json output section:
"Outputs": {
"redisHost": {
"Description": "Redis host URI",
"Value": {
"Fn::GetAtt": [
"RedisCluster",
"RedisEndpoint.Address"
]
}
}
}
s-function.json environment section:
"environment": {
"REDIS_HOST": "${redisHost}"
},
Usage in a Lambda function:
exports.handler = function(event, context) {
console.log("Redis host: ", process.env.REDIS_HOST);
};
old answer
Looks like a solution was found / implemented in the Serverless issue tracker (link). To quote HyperBrain:
CF Output variables
To have your lambda access the CF output variables you have to give it the cloudformation:describeStacks access rights in the lambda IAM role.
The CF.loadVars() promise will add all CF output variables to the process'
environment as SERVERLESS_CF_OutVar name. It will add a few ms to the
startup time of your lambda.
Change your lambda handler as follows:
// Require Serverless ENV vars
var ServerlessHelpers = require('serverless-helpers-js');
ServerlessHelpers.loadEnv();
// Require Logic
var lib = require('../lib');
// Lambda Handler
module.exports.handler = function(event, context) {
ServerlessHelpers.CF.loadVars()
.then(function() {
lib.respond(event, function(error, response) {
return context.done(error, response);
});
})
};

Resources