Deploy react app to AWS with pm2 - reactjs

I am trying to deploy react app to AWS following this tutorial https://medium.com/#sgobinda007/setting-up-react-redux-application-for-production-and-hosting-in-aws-ec2-8bbb8bf3c643 my app is slightly different and when I run pm2 start ecosystem.config.js --env production I get that app status is online but on pm2 show status is errored with the following output: /home/ubuntu/www/react/tools/distServer.js:4
import browserSync from 'browser-sync';
^^^^^^
|
| SyntaxError: Unexpected token import
my ecosystem.config.js file looks like this:
module.exports = {
apps : [
{
name: "blockchainwallet",
script: "tools/distServer.js",
watch: true,
env: {
"PORT": 8080,
"NODE_ENV": "development"
},
env_production: {
"PORT": 3000,
"NODE_ENV": "production",
}
}
]
}
could you give me any suggestions in order to fix this bug?

Check your webpack config and the node version of your environment, as the error you mention is a common error for not supported ES6 syntax.
import is used in ES6, you must use require in ES5

Related

Nrwl/React - Upload source maps to sentry

I'm working on a React application inside my NX Workspace.
Now I want to add sentry to my project. I already have a deploy configuration in my project.json. But I'm struggling with adding the step to upload the source maps.
Here is my project.json
"deploy": {
"executor": "nx:run-commands",
"options": {
"parallel": false,
"commands": [
{
"command": "nx run my-app:build:{args.target}",
"forwardAllArgs": true
},
{
"command": "echo Run {args.target} deployment on {args.server}",
"forwardAllArgs": true
},
{
"command": "rsync -avz --progress --delete dist/apps/my-app/ {args.user}#{args.server}:{args.path}",
"forwardAllArgs": true
},
{
"command": "echo my-app deployed to {args.target}",
"forwardAllArgs": true
}
]
},
"configurations": {
"production": {
"args": "--target=production --user=user --server=myserver.com --path=path/to/app"
}
}
}
Is there any example of how to perform the upload of the source maps using a nx workspace? Or do I have to create a custom script that handles everything and put it into my project.json as the second command (after build, before deploy).
Also, I'm not sure how to handle the version number of my application as NX does not provide a way to define version numbers for each application inside the workspace.
You'll have to create a custom webpack config on the Nx project: https://nx.dev/recipes/other/customize-webpack
and then follow the instructions on how to setup it on Sentry using webpack:
https://docs.sentry.io/platforms/javascript/guides/react/sourcemaps/uploading/webpack/
Your custom webpack should look like something like this:
const {merge} = require('webpack-merge')
const SentryWebpackPlugin = require('#sentry/webpack-plugin')
const nrwlConfig = require('#nrwl/react/plugins/webpack.js')
module.exports = (config) => {
// merge config from #nrwl/react first
nrwlConfig(config)
return merge(config, {
devtool: 'source-map', // Source map generation must be turned on
plugins: [
new SentryWebpackPlugin({
org: 'orgId',
project: 'projectId',
// Specify the directory containing build artifacts
include: './build',
// Auth tokens can be obtained from https://sentry.io/settings/account/api/auth-tokens/
// and needs the `project:releases` and `org:read` scopes
authToken: process.env.NX_SENTRY_AUTH_TOKEN,
// Optionally uncomment the line below to override automatic release name detection
// release: process.env.RELEASE,
}),
],
})
}
Please notice that unfortunately this is not a final answer, because with this I can upload the artifact, but the source maps are still not working on Sentry and I don't know why yet - but maybe this can be helpful somehow to you.

vitejs build with jsx returning MIME error on aws amplify

So I am using Vitejs with a react project.
I am using the jsx extension for all the react files in the appplication.
When using the npm build, then npm run preview the applicaiton is working fine on my computer locally
however when I am using aws amplify, the page is giving me a MIME error:
Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/jsx". Strict MIME type checking is enforced for module scripts per HTML spec.
Now I tried many configurations for Vite, yet nothing is working, here is my config file
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import fs from 'fs/promises';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
esbuild: {
loader: 'jsx',
},
resolve: {
alias: {
'./runtimeConfig': './runtimeConfig.browser',
},
},
optimizeDeps: {
esbuildOptions: {
loader: {
'.js': 'jsx',
},
},
},
})
for anyone that is facing the same issue, what I did is went to AWS build settings, and added:
baseDirectory: /dist
That was it 😊

How do I get HMR (Hot Module Replacement) working with a TypeScript React Monorepo in Vite

I've got a React monorepo (build in TypeScript) and I've recently been switching over from Webpack to Vite. However I'm having real difficult in getting HMR working correctly within Vite (I believe because we separately build our packages).
I'm open to options to get this working (although I think I still need to be able to build my packages, for Jest/ESLint performance).
Project Structure
\apps
\main
\packages
\domainA
\foo
\package.json
\build
\src
At the moment each package gets build using tsc "tsc --project tsconfig.lib.json" into the build directory. The package.json defines the following:
"name": "#ig/foo",
"main": "./build/index.js",
"types": "./build/index.d.ts",
"files": [
"/build"
],
I can spin up the main application and if I make a change in /packages/domainA/foo/src/index.ts then it'll build (currently using a watcher) and I get a full page reload.
I'd like to eliminate the page reload and instead use HMR. I don't think changing the entry point to "main": "./src/index.ts" will work for my use-case due to the slowness in the other tools unfortunately. However I'm happy to try and bypass this and re-point Vite to the source files if necessary.
I've tried all sorts of permutations, having looked at a few sample repos. But not managed to get anything working, e.g.
resolve: {
alias: [{
find: '#ig/foo',
replacement: '../packages/domainA/foo/src/index.ts',
},
}
Here is my current Vite config:
import react from '#vitejs/plugin-react';
import fs from 'fs';
import path, { resolve } from 'path';
import { defineConfig } from 'vite';
import mkcert from 'vite-plugin-mkcert';
import svgrPlugin from 'vite-plugin-svgr';
export default defineConfig({
// optimizeDeps: {
// include: ['#infogrid/solution-views-occupancy'],
// },
build: {
outDir: 'build/public',
sourcemap: true,
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
base: resolve(__dirname, 'index_base.html'),
},
}
},
server: {
port: Number(process.env.PORT),
// setting to true allows external ip
host: true,
},
plugins: [
react({ fastRefresh: true }), // Primarily used for HMR
svgrPlugin({ svgrOptions: { icon: true } }), // Turns svgs into react components
mkcert(), // Allows for HTTPS during local development
]
}

How to provide `babel-preset-react-app` env variables?

I am working on an App which connects create-react-app with an express server( using server rendering). I am referring this tutorial for it.To render the file from server, the code is
bootstrap.js
require('ignore-styles');
require('babel-register')({
ignore:[/(node-modules)/],
presets:['es2015','react-app']
});
require('./index');
index.js
import express from 'express';
// we'll talk about this in a minute:
import serverRenderer from './middleware/renderer';
const PORT = 3000;
const path = require('path');
// initialize the application and create the routes
const app = express();
const router = express.Router();
// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer);
// other static resources should just be served as they are
router.use(express.static(
path.resolve(__dirname, '..', 'build'),
{ maxAge: '30d' },
));
// tell the app to use the above rules
app.use(router);
// start the app
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log("listening on " + PORT + "...");
});
While running the command
node bootstrap.js
I am getting error that
Error: Using babel-preset-react-app requires that you specify NODE_ENV or BABEL_ENV environment variables. Valid values are "development", "test", and "production".
There are a few options here. I will describe the most easy options.
The most easy one is to run your node bootstrap.js like this:
NODE_ENV=production BABEL_ENV=production node bootstrap.js
But that is just too long to remember every time, so you can use package.json scripts.
If you open up your package.json file, you should see a scripts section (if not, see the doc). In that scripts section you can create your own scripts.
I mostly use 2 scripts, one for development and one for production. So in your case something like:
"scripts": {
"start": "NODE_ENV=development BABEL_ENV=development node bootstrap.js",
"serve": "NODE_ENV=production BABEL_ENV=production node bootstrap.js"
}
Now you can run your node app like this:
In development
node run start or node start (because node start is an alias for node run start)
and in production
node run serve (no shorthands here)
If you still think your package.json becomes too large, you can abstract that away to some .js files. And change your scripts accordingly to something like:
"scripts": {
"start": "node scripts/start.js"
"serve": "node scripts/serve.js"
}
In those script files you can define both of those environment variables before running your app.
For solving the next error
0:0 error Parsing error: [BABEL] {some-path}: Using `babel-preset-react-app` requires that you specify `NODE_ENV` or `BABEL_ENV` environment variables. Valid values are "development", "test", and "production". Instead, received: undefined. (While processing: "{project-path}\\node_modules\\babel-preset-react-app\\index.js")
It was useful for me to add
"parser": "#typescript-eslint/parser",
into "eslintConfig" block in the package.json of my React app.
Error: Using babel-preset-react-app requires that you specify NODE_ENV or BABEL_ENV
Answer for CRA(create react app):
#origin post https://github.com/facebook/create-react-app/issues/2377
#Error:
0:0 error Parsing error: [BABEL] {some-path}: Using `babel-preset-react-app` requires
that you specify `NODE_ENV` or `BABEL_ENV` environment variables. Valid values are "development", "test", and "production". Instead, received: undefined. (While processing: "{project-path}\\node_modules\\babel-preset-react-app\\index.js")
#Description:
Problem occured after added .babelrc file to CRA using #rescripts/cli and #rescripts/rescript-use-babel-config.
For fix error you should:
Typescript:
Added "parser": "#typescript-eslint/parser", to your eslint.
Javascript:
Added "parser": "#babel/eslint-parser", to your eslint.
Eslint docs: https://eslint.org/docs/user-guide/configuring/plugins#specifying-parser
Example of typescript eslint config in package.json for CRA:
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest",
"eslint:recommended"
],
"globals": {
"NodeJS": true
},
"parser": "#typescript-eslint/parser",
"overrides": [
{
"files": ["*.ts", "*.tsx"],
"rules": {
"no-undef": "off",
"no-unused-vars": "off",
"#typescript-eslint/no-unused-vars": ["error"]
}
}
],
"rules": {
"no-empty": [
"error",
{
"allowEmptyCatch": true
}
]
}
}

karma-webpack not loading AngularJS bundle

I recently started the move from a custom gulp script that used to take care of all sorts of stuff to webpack. I have it working to a point where transpiling, bundling and serving the client app in the browser works great.
Now, when I was using gulp to run my karma tests against the bundled app.js file, the gulp script would first bundle the app.js file and then spit it into the dist folder. This file would then be used by karma to run the tests against it. My gulp test task would also watch for any test file changes or for the bundle file change, and re-run the tests based on that.
With webpack, I understand this dist/app.js resides in-memory, rather than being written to the disk (at least that's how I set it up). The problem with that is that it seems that my bundled app (which gets served fine with webpack-dev-server --open) does not get loaded by karma for some reason and I can't figure out what the missing piece of the puzzle is.
This is how my folder structure looks like (I left just the most basic stuff that could be relevant to the issue):
package.json
webpack.config.js
karma.conf.js
src/
--app/
----[other files/subfolders]
----app.ts
----index.ts
--boot.ts
--index.html
tests/
--common/
----services/
------account.service.spec.js
This is my webpack.config.js
var path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");
module.exports = {
context: path.join(__dirname),
entry: "./src/boot.ts",
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ForkTsCheckerWebpackPlugin(),
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
template: "./src/index.html"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
},
{
test: /\.tsx?$/,
use: [{
loader: "ts-loader",
options: {
transpileOnly: true,
exclude: /node_modules/
}
}]
},
{
test: /\.html$/,
loaders: "html-loader",
options: {
attrs: [":data-src"],
minimize: true
}
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"],
alias: {
"common": path.resolve(__dirname, "src/app/common"),
"common/*": path.resolve(__dirname, "src/app/common/*"),
"modules": path.resolve(__dirname, "src/app/modules"),
"modules/*": path.resolve(__dirname, "src/app/modules/*"),
}
},
output: {
filename: "app.js",
path: path.resolve(__dirname, "dist")
},
devtool: "inline-source-map",
devServer: {
historyApiFallback: true,
hot: false,
contentBase: path.resolve(__dirname, "dist")
}
};
This is my karma.conf.js
const webpackConfig = require("./webpack.config");
module.exports = function (config) {
config.set({
frameworks: ["jasmine"],
files: [
"node_modules/angular/angular.js",
"node_modules/angular-mocks/angular-mocks.js",
"dist/app.js", // not sure about this
"tests/common/*.spec.js",
"tests/common/**/*.spec.js"
],
preprocessors: {
"dist/app.js": ["webpack", "sourcemap"], // not sure about this either
"tests/common/*.spec.js": ["webpack", "sourcemap"],
"tests/common/**/*.spec.js": ["webpack", "sourcemap"]
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true,
stats: {
chunks: false
}
},
reporters: ["progress", "coverage"], // , "teamcity"],
coverageReporter: {
dir: "coverage",
reporters: [
{ type: "html", subdir: "html" },
{ type: "text-summary" }
]
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: [
"PhantomJS"
//"Chrome"
],
singleRun: false,
concurrency: Infinity,
browserNoActivityTimeout: 100000
});
};
This is the boot.ts which is basically the entry point to the app:
import * as app from "./app/app";
import "./styles/app.scss";
// This never gets written to the console
// so I know it never gets loaded by karma
console.log("I NEVER OUTPUT TO CONSOLE");
This is the app.ts (which then references anything below it:
import * as ng from "angular";
import * as _ from "lodash";
import "#uirouter/angularjs";
import "angular-cookies";
import "angular-material"
import "angular-local-storage";
import "angular-sanitize";
import "angular-messages";
import "angular-file-saver";
import "angular-loading-bar";
import "satellizer";
export * from "./index";
import * as Module from "common/module";
import * as AuthModule from "modules/auth/module";
import * as UserModule from "modules/user/module";
import { MyAppConfig } from "./app.config";
import { MyAppRun } from "./app.run";
export default ng.module("MyApp", [
"ngCookies",
"ngSanitize",
"ngMessages",
"ngFileSaver",
"LocalStorageModule",
"ui.router",
"ngMaterial",
"satellizer",
"angular-loading-bar",
Module.name,
AuthModule.name,
UserModule.name
])
.config(MyAppConfig)
.run(MyAppRun);
And finally, this is the account.service.spec.js
describe("Account service", function () {
// SETUP
var _AccountService;
beforeEach(angular.mock.module("MyApp.Common"));
beforeEach(angular.mock.inject(function (_AccountService_) {
// CODE NEVER GETS IN HERE EITHER
console.log("I NEVER OUTPUT TO CONSOLE");
_AccountService = _AccountService_;
}));
function expectValidPassword(result) {
expect(result).toEqual({
minCharacters: true,
lowercase: true,
uppercase: true,
digits: true,
isValid: true
});
}
// TESTS
describe(".validatePassword()", function () {
describe("on valid password", function () {
it("returns valid true state", function () {
expectValidPassword(_AccountService.validatePassword("asdfASDF123"));
expectValidPassword(_AccountService.validatePassword("as#dfAS!DF123%"));
expectValidPassword(_AccountService.validatePassword("aA1234%$2"));
expectValidPassword(_AccountService.validatePassword("YYyy22!#"));
expectValidPassword(_AccountService.validatePassword("Ma#38Hr$"));
expectValidPassword(_AccountService.validatePassword("aA1\"#$%(#/$\"#$/(=/#$=!\")(\")("));
})
});
});
});
And this is the output of running the karma start
> npm test
> myapp#1.0.0 test E:\projects\Whatever
> karma start
clean-webpack-plugin: E:\projects\Whatever\dist has been removed.
Starting type checking service...
Using 1 worker with 2048MB memory limit
31 10 2017 21:47:23.372:WARN [watcher]: Pattern "E:/projects/Whatever/dist/app.js" does not match any file.
31 10 2017 21:47:23.376:WARN [watcher]: Pattern "E:/projects/Whatever/tests/common/*.spec.js" does not match any file.
ts-loader: Using typescript#2.4.2 and E:\projects\Whatever\tsconfig.json
No type errors found
Version: typescript 2.4.2
Time: 2468ms
31 10 2017 21:47:31.991:WARN [karma]: No captured browser, open http://localhost:9876/
31 10 2017 21:47:32.004:INFO [karma]: Karma v1.7.1 server started at http://0.0.0.0:9876/
31 10 2017 21:47:32.004:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
31 10 2017 21:47:32.010:INFO [launcher]: Starting browser PhantomJS
31 10 2017 21:47:35.142:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket PT-pno0eF3hlcdNEAAAA with id 71358105
PhantomJS 2.1.1 (Windows 8 0.0.0) Account service .validatePassword() on valid password returns valid true state FAILED
forEach#node_modules/angular/angular.js:410:24
loadModules#node_modules/angular/angular.js:4917:12
createInjector#node_modules/angular/angular.js:4839:30
WorkFn#node_modules/angular-mocks/angular-mocks.js:3172:60
loaded#http://localhost:9876/context.js:162:17
node_modules/angular/angular.js:4958:53
TypeError: undefined is not an object (evaluating '_AccountService.validatePassword') in tests/common/services/account.service.spec.js (line 742)
webpack:///tests/common/services/account.service.spec.js:27:0 <- tests/common/services/account.service.spec.js:742:44
loaded#http://localhost:9876/context.js:162:17
PhantomJS 2.1.1 (Windows 8 0.0.0) Account service .validatePassword() on valid amount of characters returns minCharacters true FAILED
forEach#node_modules/angular/angular.js:410:24
loadModules#node_modules/angular/angular.js:4917:12
createInjector#node_modules/angular/angular.js:4839:30
WorkFn#node_modules/angular-mocks/angular-mocks.js:3172:60
node_modules/angular/angular.js:4958:53
TypeError: undefined is not an object (evaluating '_AccountService.validatePassword') in tests/common/services/account.service.spec.js (line 753)
webpack:///tests/common/services/account.service.spec.js:38:0 <- tests/common/services/account.service.spec.js:753:37
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 2 of 2 (2 FAILED) ERROR (0.017 secs / 0.015 secs)
Please note the few places where I left console.logs which never get triggered. That's how I know the app doesn't get loaded. That and the fact that jasmine is not able to inject the service I want to test.
I'm using:
karma v1.7.1
karma-webpack v2.0.5
webpack v3.3.0
Any ideas? What am I doing wrong? I'm under the impression that my webpack.config.js is supposed to bundle my AngularJS/TS app and then essentially feed it to karma, but for whatever reason, that doesn't seem to work. Or do I have some fundamental misconception of how this is supposed to work?
Thank you.
I extracted a few files into a simple app and put it to github so the issue could be easily reproduced.
npm install # install deps
npm run serve:dev # run the app - works
npm run test # run karma tests - doesn't work
Edit:
I managed to make the tests run by replacing the:
"dist/app.js"
in karma setup with
"src/boot.ts"
but that wouldn't drill down or load/import the rest of the app. Then I tried importing only the class I want to test to the spec but then I couldn't mock any DI-injected services that the class I'm testing is using. Anyway, I pretty much gave up on this at this stage and stopped trying to figure out how to do this, moving to ang2+.
I faced a similar issue during transferring my AngularJS project building from Grunt to Webpack and tried 2 different approaches.
1. Webpack and Karma as two separate processes. I made an npm-script running webpack and karma in parallel. It looked like
"dev-build": "webpack --config webpack/development.js",
"dev-test": "karma start test/karma.development.conf.js",
"test": "concurrently --kill-others --raw \"npm run dev-build\" \"npm run dev-test\""
Instead of concurrently you may do anything else, npm-run-all or even &. In that configuration Karma did not have any Webpack stuff, she just watched the ./temp folder for built distributive and worked stand-alone, re-running herself each time the tests or distributive had been changed. Webpack was started in the dev-mode (via "dev-build" script), he watched the ./src folder and compiled distributive into the ./temp folder. When he updated ./temp, Karma started tests re-running.
It worked, despite the problems of first Karma fail. Karma started tests before the Webpack first compilation had been finished. It's not critical. Also, a playing with restartOnFileChange setting could help... Maybe there is another good workaround. I didn't finished this story, I switched to option 2, which I believe fits the Webpack-way a bit more than just described one.
2. Karma is the only process, which uses Webpack. I refused the ./temp folder and decided that for the dev-mode all operations should be in-memory. Dev-mode Webpack got following settings (./webpack/development.js):
entry: { 'ui-scroll': path.resolve(__dirname, '../src/ui-scroll.js') },
output: { filename: '[name].js' }, // + path to ./dist in prod
devtool: 'inline-source-map', // 'source-map' in prod
compressing: false,
watch: true
Dev-mode Karma (./test/karma.development.conf.js):
files: [
// external libs
// tests specs
'../src/ui-scroll.js' // ../dist in prod
],
preprocessors: { // no preprocessors in prod
'../src/ui-scroll.js': ['webpack', 'sourcemap']
},
webpack: require('../webpack/development.js'), // no webpack in prod
autoWatch: true,
keepalive: true,
singleRun: false
This also required two npm packages to be installed: karma-webpack and karma-sourcemap-loader. The first option looks more familiar after Grunt/gulp, but this one is simpler, shorter and more stable.

Resources