I created a simple react application using npx create-react-app and made minor modifications which looks like this initially.
Initial Page
I then build it and deployed it to S3 bucket. I have enabled static website hosting, enabled public access and set bucket policy as
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::s3-demo-react/*"
}
]
}
But the S3 bucket url displayed Blank White Screen like this
White Screen on Initial Deployment
I researched and came up with answer to add homepage to my package.json. My Package.json looks like this after the change.
{
"name": "s3-app",
"homepage": "./",
"version": "0.1.0",
"private": true,
I build the project and the asset-manifest.json inside build file has following code
{
"files": {
"main.css": "./static/css/main.073c9b0a.css",
"main.js": "./static/js/main.d4f30fdf.js",
"static/js/787.668da4e5.chunk.js": "./static/js/787.668da4e5.chunk.js",
"static/media/logo.svg": "./static/media/logo.6ce24c58023cc2f8fd88fe9d219db6c6.svg",
"index.html": "./index.html",
"main.073c9b0a.css.map": "./static/css/main.073c9b0a.css.map",
"main.d4f30fdf.js.map": "./static/js/main.d4f30fdf.js.map",
"787.668da4e5.chunk.js.map": "./static/js/787.668da4e5.chunk.js.map"
},
"entrypoints": [
"static/css/main.073c9b0a.css",
"static/js/main.d4f30fdf.js"
]
}
I redeployed the application but the same issue persist.
Still the whitescreen with css and js 404
I watched few videos on deployment where all of them hosted their site even without specifying homepage in package.json and it worked as expected for them. Am I missing something here?
I've got a frontend (next.js) which has tailwindcss installed (config, postcss, ...) and everything works.
I've made another package (ui) which has the following package.json
{
"name": "ui",
"version": "1.0.0",
"private": true,
"peerDependencies": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"autoprefixer": "^10.3.2",
"postcss": "^8.3.6",
"tailwindcss": "^2.2.7"
}
}
The problem is when is serve the ui locally everything works fine (the UI sees the styles of the component), but when deployed to vercel, the component has no styles in it.
The component (ui):
import React from 'react';
const Example = ({children}) => <button className='bg-blue-500 py-1 px-2'>{children}</button>
export default Example
And my next config (frontend)
const withTM = require('next-transpile-modules')(['bar'])
module.exports = withTM()
Is there a way of sharing the same tailwind.config.js ? Or anything to make it work.
Steps that I have made:
created the workspace
added frontend package (next, and then i installed tailwind with all the steps from their docs)
added the ui package (installed the peerDependencies, see above)
created the component
added the ui package as a dependency in the frontend, yarn install, and then imported the component
yarn dev, and the styles are applied locally.
deployed to vercel, the button has only the children , no styles
UPDATE:
The problem is caused by the purging process at build time.
Is there any way to specify in the tailwind config to purge also the ui package?
UPDATE2:
I've tried to add the package (i've renamed it to "#example/ui") to the purge in next.config.js
module.exports = {
purge: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./node_modules/#example/ui/src/*.{js,ts,jsx,tsx}'
],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
},
variants: {
extend: {},
},
plugins: [],
}
The code in the UI package is inside of the src, has only the index.tsx file. I mention, locally still works fine.
Solved it !
In the purge array , I needed to add the node modules from the root of the project, not of the frontend
create-react-app docs says you can configure your proxy objects manually. I'm following the http-proxy-middleware docs on matching
to exclude a specific route but haven't got it to work.
Basically I'm serving my app from the /app route instead of root. So I want the following to happen:
/app/api proxies to http://localhost:3001, my backend service
All requests that does NOT start with /app proxy to http://cloud.my-app.com
This is what I've tried so far with no luck:
"homepage": "https://cloud.my-app.com/app",
"proxy": {
"/app/api": { // Works
"target": "http://localhost:3001"
},
"!/app/*": { // Does not work
"target": "https://cloud.my-app.com",
"secure": false
}
},
What am I missing?
Add the below as your proxy:
"proxy": {
"/app/api":{
"target":"http://localhost:3001",
},
"/.*/":{
"target":"https://cloud.my-app.com",
"secure":"false",
"changeOrigin": true
}
}
I'm having issues setting up an React project with yarn workspaces and typescript.
My folder structure is:
-root
-package.json
-workspaces
-web
-common
and my package.json file is:
{
"name": "my-project-name",
"private": true,
"workspaces": [
"workspaces/web",
"workspaces/common"
],
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
]
}
My issue is: when I import files on web from the common project, it works fine if it's a .js file, but fails with TypeError: Object(...) is not a function when using .ts or .tsx files.
Any ideas on what I might be missing?
I recommend adopting the following file hierarchy:
- root
- package.json
- tsconfig.json
- packages
- common
- package.json
- tsconfig.json
- services
- web
- package.json
- tsconfig.json
Everything in the packages folder can be imported. Services are "leaf" projects that you don't want to import in other projects.
With that as a base, your root package.json should be setup like that:
{
"name": "my-project-name",
"private": true,
"workspaces": [
"packages": [
"packages/*",
"services/**/*"
],
],
}
Then, you also need to tell typescript how to resolve the imports.
In the root tsconfig.json, set the following:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#myproject/*": ["packages/*/src"]
},
}
Make sure that every tsconfig extends this base with "extends": "../../tsconfig.json"
Inside web/package.json or any package that needs to import common, define common as a dependency:
{
[...]
"dependencies": {
"#myproject/common": "*",
}
}
Now if your common package.json has a name set to `"#myproject/common", you can import your code inside web with :
import { myUtilFunction } from "#myproject/common";
I would advise you to also use learn with a setup like this.
You will also need to modify a bit your build pipeline, since you're importing files inside /web that are outside the /web folder. For a more complete example, you can check out this repo: https://github.com/NiGhTTraX/ts-monorepo
I'm writing a web app using react and webpack as my module bundler.
My jsx code is really light so far, the size of the entire folder is 25 kb.
My bundle.js created from webpack is 2.2 mb though. After running the optimization with the -p flag, it reduces the bundle to 700kb, which is still extremely big.
I have looked into the react.min.js file and its size is 130kb.
Is it possible that the webpack produces such big files or am I doing something wrong?
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './public/components/main.jsx',
output: {
path: __dirname + "/public",
filename: 'bundle.js'
},
module: {
loaders: [{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}, {
test: /\.css$/,
loader: "style!css"
}]
}
};
EDIT
package.json:
{
"name": "XChange",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"main": "./bin/www",
"devDependencies": {
"body-parser": "~1.13.2",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"express": "~4.13.1",
"jade": "~1.11.0",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0",
"react-dom": "~0.14.3",
"react": "~0.14.3",
"webpack": "~1.12.9",
"babel-loader": "~6.2.0",
"babel-core": "~6.2.1",
"babel-preset-react": "~6.1.18",
"babel-preset-es2015": "~6.1.18",
"react-bootstrap": "~0.28.1",
"material-ui": "~0.14.0-rc1",
"history": "~1.13.1",
"react-router": "~1.0.2",
"style-loader": "~0.13.0",
"css-loader": "~0.18.0"
},
"dependencies": {
"express-validator": "~2.18.0",
"mongoose": "~4.2.9",
"kerberos": "~0.0.17",
"bcrypt": "~0.8.5"
}
}
According to your comments you are using material-ui and react-bootstrap. Those dependencies are bundled by webpack along with your react and react-dom packages. Any time you require or import a package it is bundled as part of your bundle file.
And here it comes my guess. You are probably importing the react-bootstrap and material-ui components using the library way:
import { Button } from 'react-bootstrap';
import { FlatButton } from 'material-ui';
This is nice and handy but it does not only bundles Button and FlatButton (and their dependencies) but the whole libraries.
One way to alleviate it is to try to only import or require what is needed, lets say the component way. Using the same example:
import Button from 'react-bootstrap/lib/Button';
import FlatButton from 'material-ui/lib/flat-button';
This will only bundle Button, FlatButton and their respective dependencies. But not the whole library. So I would try to get rid of all your library imports and use the component way instead.
If you are not using lot of components then it should reduce considerably the size of your bundled file.
As further explanation:
When you are using the library way you are importing all these react-bootstrap and all these material-ui components, regardless which ones you are actually using.
01/2017 EDIT - I've since learned a little more about different Webpack Plugins, and wanted to update this. It turns out that UglifyJS has a littany of config options that don't seem to be very mainstream, but can have a dramatic effect on your bundle size. This is my current config w/ some annotations (docs on site are great):
new webpack.optimize.UglifyJsPlugin({
comments: false, // remove comments
compress: {
unused: true,
dead_code: true, // big one--strip code that will never execute
warnings: false, // good for prod apps so users can't peek behind curtain
drop_debugger: true,
conditionals: true,
evaluate: true,
drop_console: true, // strips console statements
sequences: true,
booleans: true,
}
})
I once encountered an obscure problem with uglify-ication of escaped unicode chars, so be mindful if you employ these transformations that edge-case things like that are possible.
You can read more about the specific options webpack supports in the webpack docs w/ some follow-on links to further reading.
(sidenote: I think your package.json is mixed-up... at least a few of those dev-dependencies are dependencies in every package.json I've seen (e.g., the react-starter-kit)
If you're preparing for production, there are a few more steps you should take to get your file size down. Here's a snip of my webpack.config.js:
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
})
],
1) minifies/uglifies your code
2) replaces duplicate code to minimize file-size
3) tells webpack to omit some things it uses for node environment builds
Finally, if you use a source map (which you probably should), you'll want to add the appropriate line. Sentry wrote a nice blog post about this.
In my build, i use devtool: 'source-map' for production
UPDATED 05/18 : update UglifyJsPlugin setting for better minification
I use below configuration for the minification in production code.
plugins: [
new webpack.DefinePlugin({
'process.env': {
// This has effect on the react lib size
'NODE_ENV': JSON.stringify('production'),
}
}),
new ExtractTextPlugin("bundle.css", {allChunks: false}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true
},
output: {
comments: false,
},
exclude: [/\.min\.js$/gi] // skip pre-minified libs
}),
new webpack.IgnorePlugin(/^\.\/locale$/, [/moment$/]),
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0
})
],
Have you looked at how you're scripts are being sent over the wire... I had some very simple react components that were up around 300kb each, and that was after the webpack optimizations.
After they were gzipped they came down to 38kb. Still sizable - but that's what we get for using tomorrows features today.
If you're using node/express to serve static resources, including your javascript - look at compression (https://github.com/expressjs/compression).
I'd also suggest looking at the node best practices guide for production https://expressjs.com/en/advanced/best-practice-performance.html
If you're not serving files through node, then apache (or other webserver) will have options for compressing text based files.
I find it useful to mention the source-map-explorer utility that helps in knowing what exactly is in your bundle.js file. It can help you identify if there are any unnecessary things in bundle js.
you can install the source-map-explorer from npm and use it like
source-map-explorer yourBundle.js
Besides this, as mentioned by #kimmiju , check if your server is using some compression.
You can also try to asynchronously load routes (lazy loading in webpack) , so that your entire bundlejs file is not sent in one go , instead it is sent in chunks when user navigates to those routes.