How do I use a different .env file when starting a webServer in Playwright? - node.js

I am introducing Playwright into my project. My current project structure has a separate backend and frontend in a single repo, and Playwright is installed in the frontend part of the project.
├ .git
├ frontend/
│ ├ ...
│ ├ playwright.config.ts
│ ├ .env
│ └ package.json
└ backend/
├ ...
├ server.js
├ .env
└ package.json
When I run npx playwright test from within /frontend, I want both my frontend and backend services to start up.
// playwright.config.ts
webServer: [
{
// start frontend
command: "npm run start",
port: 3000,
reuseExistingServer: !process.env.CI,
},
{
// start backend
command: "cd ../backend && node server",
port: 3001,
reuseExistingServer: !process.env.CI,
},
]
However, the environment variables that are specified in /frontend/.env are the ones that are being passed to the backend, so the backend has an incomplete or faulty configuration when it attempts to start. I have tried using the env property and specifying the path to the backend .env file in dotenv.config(), but then it overrides the frontend environment variables, giving me the same but opposite problem.
How can I get /backend/.env to be used by the backend process, and /frontend/.env to be used by the frontend process?

You can force dotenv to read each of the .env files and then cache the value of process.env. Then I could pass the environment variables to each webserver with the env property. Since I want /frontend/.env to be loaded into process.env, I load /backend/.env first.
override: true is required for the second call of dotenv.config() if you have conflicting environment variables, such as PORT. By default, dotenv will not set environment variables that already exist, so any variables with the same name will not get set.
import type { PlaywrightTestConfig } from "#playwright/test";
import dotenv from "dotenv";
dotenv.config({ path: "../backend/.env", override: true });
const backendEnv = { ...process.env } as { [key: string]: string };
dotenv.config({ override: true });
const frontendEnv = { ...process.env } as { [key: string]: string };
const config: PlaywrightTestConfig = {
// omitted config above...
webServer: [
{
command: "npm run start",
port: 3000,
reuseExistingServer: !process.env.CI,
env: frontendEnv,
},
{
command: "cd ../backend && node server",
port: 3001,
reuseExistingServer: !process.env.CI,
env: backendEnv,
},
],
}

Related

My React App Unit Tests Jest is breaking: function(module,exports,require,__dirname,__filename,jest) Cannot use import statement outside a module

I'm facing a problem when trying to run the Jest tests (NextJs app) with my component library.
My React library
I'm using this command to build the React library:
"build-esm": "tsc --project tsconfig.build.json",
"build-cjs": "tsc --project tsconfig.build.json --module commonjs --outDir lib/cjs",
"build": "rm -fr lib/ && npm run build-esm && npm run build-cjs"
Will generate it:
package.json:
(...)
"main": "./lib/cjs/index.js",
"module": "./lib/esm/index.js",
"types": "./lib/esm/index.d.ts",
(...)
My "Nextjs client project" (that will use the lib as a dependency):
jest.config.js
// jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './'
});
// Add any custom config to be passed to Jest
/** #type {import('jest').Config} */
const customJestConfig = {
// Add more setup options before each test is run
setupFilesAfterEnv: ['./jest.setup.js'],
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules'],
testEnvironment: 'jest-environment-jsdom',
transformIgnorePatterns: ['<rootDir>/node_modules/']
};
// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig);
console error:
(...)/node_modules/nanoid/index.browser.js:1
({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { urlAlphabet } from './url-alphabet/index.js'
^^^^^^
SyntaxError: Cannot use import statement outside a module
8 | var react_window_1 = require("react-window");
9 | var react_window_infinite_loader_1 = __importDefault(require("react-window-infinite-loader"));
> 10 | var nanoid_1 = require("nanoid");
I appreciate any support

Vite: Could not resolve entry module (index.html)

I am new to Openshift 3.11 deployment, I created a Multistage Dockerfile for a React application, the build want correctly on my local machine, but when I run on the openshift cluster I get the error below:
> kncare-ui#0.1.0 build
> tsc && vite build
vite v2.9.9 building for production...
✓ 0 modules transformed.
Could not resolve entry module (index.html).
error during build:
Error: Could not resolve entry module (index.html).
at error (/app/node_modules/rollup/dist/shared/rollup.js:198:30)
at ModuleLoader.loadEntryModule (/app/node_modules/rollup/dist/shared/rollup.js:22680:20)
at async Promise.all (index 0)
error: build error: running 'npm run build' failed with exit code 1
and this is my Dockefile
FROM node:16.14.2-alpine as build-stage
RUN mkdir -p /app/
WORKDIR /app/
RUN chmod -R 777 /app/
COPY package*.json /app/
COPY tsconfig.json /app/
COPY tsconfig.node.json /app/
RUN npm ci
COPY ./ /app/
RUN npm run build
FROM nginxinc/nginx-unprivileged
#FROM bitnami/nginx:latest
COPY --from=build-stage /app/dist/ /usr/share/nginx/html
#CMD ["nginx", "-g", "daemon off;"]
ENTRYPOINT ["nginx", "-g", "daemon off;"]
EXPOSE 80
Vite by default uses an html page as an entry point. So you either need to create one or if you don't have an html page you can use it in "Library Mode".
https://vitejs.dev/guide/build.html#library-mode
From the docs:
// vite.config.js
const path = require('path')
const { defineConfig } = require('vite')
module.exports = defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'lib/main.js'),
name: 'MyLib',
fileName: (format) => `my-lib.${format}.js`
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue'
}
}
}
}
})
If you're using ES Modules (i.e., import sytax):
Look in your package.json to confirm type field is set to module:
// vite.config.js
import * as path from 'path';
import { defineConfig } from "vite";
const config = defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'lib/main.js'),
name: 'MyLib',
fileName: (format) => `my-lib.${format}.js`
},
rollupOptions: {
// make sure to externalize deps that shouldn't be bundled
// into your library
external: ['vue'],
output: {
// Provide global variables to use in the UMD build
// for externalized deps
globals: {
vue: 'Vue'
}
}
}
}
})
export default config;
Had same issue because of .dockerignore. Make sure your index.html not ignored.
In case if you ignoring everything (**) you can add !index.html to the next line and try.

Including a shared project in create-react-app

In my project i have the following folder/project structure.
Project
├── client (create-react-app)
│ ├── tsconfig.json
│ └── packages.json
├── server
│ ├── tsconfig.json
│ └── packages.json
└── shared
├── tsconfig.json
└── packages.json
The shared project is mostly interface/class type declarations that i use in both the front and backend so they use the same object type.
I was including the shared project in both client and server using the referenced projects from typescript.
tsconfig.json
...
},
"references": [
{
"path": "../shared"
}
],
Although upon trying to use one of the imported types in a useReducer hook:
Component in client/src
import React, { useReducer, useEffect } from 'react';
import { IRoadBook, GetNewRoadBook} from '../../../shared/src/types/IRoadBook';
import { Grid, TextField, Button } from '#material-ui/core';
import { useParams } from 'react-router-dom';
type State = {
RoadBook: IRoadBook | any;
}
export default function RoadBookEditor() {
const { objectId } = useParams();
const [state, dispatch] = useReducer(reducer, {RoadBook : GetNewRoadBook()});
....
The following error happens upon starting the project :
"Module not found: You attempted to import ../../../shared/src/types/IRoadBook which falls outside of the project src/ directory. Relative imports outside
of src/ are not supported."
Which from what i read is a limitation imposed by create-react-app configurations.
If i do
const [state, dispatch] = useReducer(reducer, {RoadBook :{}});
Code builds/runs successfuly. (causes visual issues down the road but that is not the point of this question).
Question : What is the proper way to include this shared project in my create-react-app client project?
shared/types/IRoadBook.tsx
export interface IRoadBook {
_id: string;
Name: string;
Description: string;
}
export function GetNewRoadBook(): IRoadBook {
return { _id: '', Name: '', Description: '' } as IRoadBook;
}
If I understood correctly what you're looking for is a monorepo setup.
Out of the box create-react-app does not support importing code from outside your source folder. To achieve it you need to modify the webpack config inside it, and there are a couple of alternatives for that:
1- Using something like customize-cra, craco, etc.
2- forking CRA and modifying react-scripts (https://create-react-app.dev/docs/alternatives-to-ejecting/)
3- Ejecting and modifying the webpackconfig
for 2 and 3, you'll need to remove ModuleScopePlugin from webpack config and add the paths to babel-loader.
A few other places you can get a direction:
Create React App + Typescript In monorepo code sharing
https://blog.usejournal.com/step-by-step-guide-to-create-a-typescript-monorepo-with-yarn-workspaces-and-lerna-a8ed530ecd6d

Using Environment Variables with Vue.js

I've been reading the official docs and I'm unable to find anything on environment variables. Apparently there are some community projects that support environment variables but this might be overkill for me. So I was wondering if there's something simple out of the box that works natively when working on a project already created with Vue CLI.
For example, I can see that if I do the following the right environment prints out meaning this is already setup?
mounted() {
console.log(process.env.ROOT_API)
}
I'm a kinda new to env variables and Node.
FYI using Vue CLI version 3.0 beta.
Vue.js with Webpack
If you use vue cli with the Webpack template (default config), you can create and add your environment variables to a .env file.
The variables will automatically be accessible under process.env.variableName in your project. Loaded variables are also available to all vue-cli-service commands, plugins and dependencies.
You have a few options, this is from the Environment Variables and Modes documentation:
.env # loaded in all cases
.env.local # loaded in all cases, ignored by git
.env.[mode] # only loaded in specified mode
.env.[mode].local # only loaded in specified mode, ignored by git
Your .env file should look like this:
VUE_APP_MY_ENV_VARIABLE=value
VUE_APP_ANOTHER_VARIABLE=value
As noted in comment below:
If you are using Vue cli 3, only variables that start with VUE_APP_ will be loaded.
Don't forget to restart serve if it is currently running.
Vue.js with Vite
Vite exposes env variables that start with VITE_ on the special import.meta.env object.
Your .env should look like this:
VITE_API_ENDPOINT=value
VITE_API_KEY=value
These variables can be accessed in Vue.js components or JavaScript files under import.meta.env.VITE_API_ENDPOINT and import.meta.env.VITE_API_KEY.
Tip: Remember to restart your development server whenever you change or add a variable in the .env file if it's running.
For more info, please see the Vite documentation for env variables.
If you are using Vue cli 3, only variables that start with VUE_APP_ will be loaded.
In the root create a .env file with:
VUE_APP_ENV_VARIABLE=value
And, if it's running, you need to restart serve so that the new env vars can be loaded.
With this, you will be able to use process.env.VUE_APP_ENV_VARIABLE in your project (.js and .vue files).
Update
According to #ali6p, with Vue Cli 3, isn't necessary to install dotenv dependency.
Create two files in root folder (near by package.json) .env and .env.production
Add variables to theese files with prefix VUE_APP_ eg: VUE_APP_WHATEVERYOUWANT
serve uses .env and build uses .env.production
In your components (vue or js), use process.env.VUE_APP_WHATEVERYOUWANT to call value
Don't forget to restart serve if it is currently running
Clear browser cache
Be sure you are using vue-cli version 3 or above
For more information: https://cli.vuejs.org/guide/mode-and-env.html
In the root of your project create your environment files:
.env
.env.someEnvironment1
.env.SomeEnvironment2
To then load those configs, you would specify the environment via mode i.e.
npm run serve --mode development //default mode
npm run serve --mode someEnvironment1
In your env files you simply declare the config as key-value pairs, but if you're using vue 3, you must prefix with VUE_APP_:
In your .env:
VUE_APP_TITLE=This will get overwritten if more specific available
.env.someEnvironment1:
VUE_APP_TITLE=My App (someEnvironment1)
You can then use this in any of your components via:
myComponent.vue:
<template>
<div>
{{title}}
</div>
</template>
<script>
export default {
name: "MyComponent",
data() {
return {
title: process.env.VUE_APP_TITLE
};
}
};
</script>
Now if you ran the app without a mode it will show the 'This will get...' but if you specify a someEnvironment1 as your mode then you will get the title from there.
You can create configs that are 'hidden' from git by appending .local to your file: .env.someEnvironment1.local - very useful for when you have secrets.
Read the docs for more info.
A problem I was running into was that I was using the webpack-simple install for VueJS which didn't seem to include an Environment variable config folder. So I wasn't able to edit the env.test,development, and production.js config files. Creating them didn't help either.
Other answers weren't detailed enough for me, so I just "fiddled" with webpack.config.js. And the following worked just fine.
So to get Environment Variables to work, the webpack.config.js should have the following at the bottom:
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
Based on the above, in production, you would be able to get the NODE_ENV variable
mounted() {
console.log(process.env.NODE_ENV)
}
Now there may be better ways to do this, but if you want to use Environment Variables in Development you would do something like the following:
if (process.env.NODE_ENV === 'development') {
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
})
]);
}
Now if you want to add other variables with would be as simple as:
if (process.env.NODE_ENV === 'development') {
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"',
ENDPOINT: '"http://localhost:3000"',
FOO: "'BAR'"
}
})
]);
}
I should also note that you seem to need the "''" double quotes for some reason.
So, in Development, I can now access these Environment Variables:
mounted() {
console.log(process.env.ENDPOINT)
console.log(process.env.FOO)
}
Here is the whole webpack.config.js just for some context:
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
if (process.env.NODE_ENV === 'development') {
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"',
ENDPOINT: '"http://localhost:3000"',
FOO: "'BAR'"
}
})
]);
}
This is how I edited my vue.config.js so that I could expose NODE_ENV to the frontend (I'm using Vue-CLI):
vue.config.js
const webpack = require('webpack');
// options: https://github.com/vuejs/vue-cli/blob/dev/docs/config.md
module.exports = {
// default baseUrl of '/' won't resolve properly when app js is being served from non-root location
baseUrl: './',
outputDir: 'dist',
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
// allow access to process.env from within the vue app
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
})
]
}
};
In vue-cli version 3:
There are the three options for .env files:
Either you can use .env or:
.env.test
.env.development
.env.production
You can use custom .env variables by using the prefix regex as /^/ instead of /^VUE_APP_/ in /node_modules/#vue/cli-service/lib/util/resolveClientEnv.js:prefixRE
This is certainly not recommended for the sake of developing an open source app in different modes like test, development, and production of .env files. Because every time you npm install .. , it will be overridden.
In addition to the previous answers, if you're looking to access VUE_APP_* env variables in your sass (either the sass section of a vue component or a scss file), then you can add the following to your vue.config.js (which you may need to create if you don't have one):
let sav = "";
for (let e in process.env) {
if (/VUE_APP_/i.test(e)) {
sav += `$${e}: "${process.env[e]}";`;
}
}
module.exports = {
css: {
loaderOptions: {
sass: {
data: sav,
},
},
},
}
The string sav seems to be prepended to every sass file that before processing, which is fine for variables. You could also import mixins at this stage to make them available for the sass section of each vue component.
You can then use these variables in your sass section of a vue file:
<style lang="scss">
.MyDiv {
margin: 1em 0 0 0;
background-image: url($VUE_APP_CDN+"/MyImg.png");
}
</style>
or in a .scss file:
.MyDiv {
margin: 1em 0 0 0;
background-image: url($VUE_APP_CDN+"/MyImg.png");
}
from https://www.matt-helps.com/post/expose-env-variables-vue-cli-sass/
Important (in Vue 4 and likely Vue 3+ as well!): I set VUE_APP_VAR but could NOT see it by console logging process and opening the env object. I could see it by logging or referencing process.env.VUE_APP_VAR. I'm not sure why this is but be aware that you have to access the variable directly!
For those using Vue CLI 3 and the webpack-simple install, Aaron's answer did work for me however I wasn't keen on adding my environment variables to my webpack.config.js as I wanted to commit it to GitHub. Instead I installed the dotenv-webpack plugin and this appears to load environment variables fine from a .env file at the root of the project without the need to prepend VUE_APP_ to the environment variables.
I am having same problem in vuecli#5. Trying to solve by reading official doc but can't get proper solution. After long time i got solution and it works fine.
Create .env file on root dir. touch .env
Set value on it i.e APP_NAME=name
vue.config.js file past it process.env.VUE_APP_VERSION = require('./package.json').version
Log to any method console.log(process.env.APP_NAME);
Running multiple builds with different .env files 🏭
In my app I wanted to have multiple production builds, one for a web app, and another for a browser extension.
In my experience, changing build modes can have side effects as other parts of the build process can rely on being in production for example, so here's another way to provide a custom env file (based on #GrayedFox's answer):
package.json
{
"scripts": {
"build": "vue-cli-service build",
"build:custom": "VUE_CLI_SERVICE_CONFIG_PATH=$PWD/vue.config.custom.js vue-cli-service build",
}
}
vue.config.custom.js
// install `dotenv` with `yarn add -D dotenv`
const webpack = require("webpack");
require("dotenv").config({ override: true, path: "./.env.custom" });
module.exports = {
plugins: [new webpack.EnvironmentPlugin({ ...process.env })],
};
Note 1: VUE_CLI_SERVICE_CONFIG_PATH swaps out the config from the default of vue.config.js, so any settings set in there will not apply for the custom build.
Note 2: this will load .env.production before .env.custom, so if you don't want any of the environment variables set in .env.production in your custom build, you'll want to set those to a blank string in .env.custom.
Note 3: If you don't set override: true then environment variables in .env.production will take precedence over .env.custom.
Note 4: If you are looking to have multiple different builds using vue-cli, the --skip-plugins option is very useful.
**just install this **
npm install -g #vue/cli
at your project
it is worked with me

How to define port dynamically in proxy.conf.json or proxy.conf.js

I have angular4 application, and for development purposes i start it with npm run start with start defined as "start": "ng serve --proxy=proxy.conf.json". Also I have
{
"/api/**": {
"target": "http://localhost:8080/api/"
}
}
defined in proxy.conf.json.
Is there a way, to define port or whole url dynamically. Like npm run start --port=8099?
PS
http://localhost:8080/api/ is URL of my backend API.
I also did not find way to interpolate .json file but you can use .js file
e.g.
proxy.conf.js
var process = require("process");
var BACKEND_PORT = process.env.BACKEND_PORT || 8080;
const PROXY_CONFIG = [
{
context: [
"/api/**"
],
target: "http://localhost:"+BACKEND_PORT+"/api/
},
];
module.exports = PROXY_CONFIG;
add new command to package.json (notice .js not .json)
"startOn8090": "BACKEND_PORT=8090 && ng serve --proxy=proxy.conf.js"
or simply set env variable in your shell script and call npm run-script start
In .angular.cli.json
....
"defaults": {
"serve": {
"port": 9000
}
}
....
makes the proxy available on port 9000 rather than the default 4200.

Resources