I am creating a React project using Typescript and I am creating it from scratch without CRA. But I am facing difficulties. I think the error is due to adding typescript and configuring webpack config file for it.
I am unable to find the error here. Please help. I am using typescript.
PFA code
webpack.config.json
Configuration file for webpack
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const isProd = process.env.NODE_ENV === 'production';
const mode = isProd ? 'production' : 'development';
const cssDev = ['style-loader', 'css-loader'];
const cssProd = [MiniCssExtractPlugin.loader, 'css-loader'];
const cssConfig = isProd ? cssProd : cssDev;
const pluginDev = [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html'
})
];
const pluginProd = [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true,
removeComments: true
}
}),
new MiniCssExtractPlugin({
filename: "css/[name].[contenthash].css"
}),
new CleanWebpackPlugin()];
const pluginConfig = isProd ? pluginProd : pluginDev;
const outputDev = {
path: path.resolve(__dirname, 'build'),
filename: 'js/bundle.js',
publicPath: '/'
};
const outputProd = {
path: path.resolve(__dirname, 'build'),
filename: 'js/bundle.[contenthash].js',
publicPath: '/'
};
const outputConfig = isProd ? outputProd : outputDev;
const optimizeProd = {
minimize: true,
minimizer: [
// For webpack#5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
// `...`
new CssMinimizerPlugin(),
],
};
const optimizeConfig = isProd ? optimizeProd : null;
module.exports = {
mode: mode,
entry: './src/index.tsx',
devtool: 'inline-source-map',
output: outputConfig,
plugins: pluginConfig,
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/i,
use: cssConfig
},
{
test: /\.html$/i,
use: ['html-loader']
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|svg)$/i,
use: {
loader: "file-loader",
options: {
name: '[sha512:hash:base64:7].[ext]',
outputPath: "images"
}
}
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ],
},
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
],
},
devServer: {
historyApiFallback: true,
},
}
index.html
Index file which has a div with an id root
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=devide-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" conent="ie=edge" />
<meta name="description" content="Airbnb clone without CRA" />
<title>Scratch React Airbnb App</title>
<link rel="apple-touch-icon" sizes="180x180" href="./assets/ico/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/ico/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/ico/favicon-16x16.png">
<link rel="manifest" href="./assets/ico/site.webmanifest">
<link rel="mask-icon" href="./assets/ico/safari-pinned-tab.svg" color="#5bbad5">
<meta name="msapplication-TileColor" content="#00aba9">
<meta name="theme-color" content="#ffffff">
<link rel="stylesheet" href="./Fonts.css">
</head>
<body>
<!-- comment -->
<div id="root"></div>
</body>
</html>
App.tsx
App file with typescript
import React , {Suspense, lazy} from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import LoadingScreen from './LoadingScreen';
const Home = lazy(() => import("./Home"));
const Explore = lazy(() => import("./Explore"));
const NotFound = lazy(() => import("./NotFound"));
const App: React.FC = () => {
return (
<main>
<Suspense fallback={<LoadingScreen />}>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/explore" component={Explore} />
<Route component={NotFound} />
</Switch>
</Suspense>
</main>
)
}
export default App
Thanks
Related
What is happening is that I am consuming a Micro front-end through module federation, but even using React.Lazy the bundle (remoteEntry) is loaded at the start of the application, without accessing the route where the component is being imported.
To simulate the scenario you can access the repository and follow the steps described. click here to access.
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const webpack = require('webpack');
const dependencies = require('./package.json').dependencies;
const ModuleFederationPlugin =
require('webpack').container.ModuleFederationPlugin;
const path = require('path');
const dotenv = require('dotenv');
module.exports = (_, args) => {
return {
mode: args.mode,
entry: './src/index.js',
output: {
filename:
process.env.NODE_ENV === 'development'
? 'main.js'
: 'main.[contenthash].js',
publicPath: process.env.NODE_ENV === 'development' ? '/' : '/app/',
path: path.resolve(__dirname, 'build')
},
devServer: {
static: {
directory: path.join(__dirname, 'build')
},
port: 3001,
historyApiFallback: true
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'],
alias: {
actions: path.resolve(__dirname, 'src', 'actions'),
components: path.resolve(__dirname, 'src', 'components'),
containers: path.resolve(__dirname, 'src', 'containers'),
'custom-hooks': path.resolve(__dirname, 'src', 'custom-hooks'),
enums: path.resolve(__dirname, 'src', 'enums'),
helpers: path.resolve(__dirname, 'src', 'helpers'),
hooks: path.resolve(__dirname, 'src', 'hooks'),
images: path.resolve(__dirname, 'src', 'images'),
libs: path.resolve(__dirname, 'src', 'libs'),
middlewares: path.resolve(__dirname, 'src', 'middlewares'),
reducers: path.resolve(__dirname, 'src', 'reducers'),
sagas: path.resolve(__dirname, 'src', 'sagas'),
services: path.resolve(__dirname, 'src', 'services'),
store: path.resolve(__dirname, 'src', 'store'),
views: path.join(__dirname, 'src', 'views'),
routes: path.join(__dirname, 'src', 'routes')
},
fallback: {
fs: false,
tls: false,
net: false,
path: false,
zlib: false,
http: false,
https: false,
stream: false,
crypto: false,
'styled-components': require.resolve('styled-components'),
util: false
}
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: ['#babel/preset-react']
}
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.s[ac]ss$/i,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpg|jpeg|gif|pdf)$/,
exclude: /node_modules/,
use: ['file-loader?name=[name].[ext]']
},
{
test: /\.svg$/,
use: ['#svgr/webpack', 'url-loader']
}
]
},
plugins: [
new webpack.ProgressPlugin(),
new CleanWebpackPlugin(),
new CopyPlugin({
patterns: [{ from: 'public/config.json', to: 'config.json' }]
}),
new ModuleFederationPlugin({
name: 'connect_front',
remotes: {
connect_vim_front: `promise new Promise((resolve, reject) => fetch('${process.env.PUBLIC_URL}config.json', {
method: 'GET'
})
.then(resp => {
return resp.text();
}).then((resp) => {
const parsedResp = JSON.parse(resp);
const script = document.createElement('script');
script.src = parsedResp.REACT_APP_URL_CONNECT_VIM_FRONT || "/",
script.onload = () => {
const proxy = {
get: (request) => window.connect_vim_front.get(request),
init: (arg) => {
try {
return window.connect_vim_front.init(arg)
} catch(e) {
console.error('remote container already initialized')
}
}
}
resolve(proxy)
}
script.onerror = function() {
reject();
};
document.head.appendChild(script)
})
.catch(err => console.log(err)))`
},
shared: {
...dependencies,
react: {
singleton: true,
eager: true,
requiredVersion: dependencies.react
},
'react-dom': {
singleton: true,
eager: true,
requiredVersion: dependencies['react-dom']
}
}
}),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: './index.html',
favicon: './public/favicon.ico',
title: 'Caching'
}),
new webpack.ProvidePlugin({
process: 'process/browser'
}),
new webpack.DefinePlugin({
'process.env': JSON.stringify(
dotenv.config({
path: `${
process.env.ENVIRONMENT
? `.env.${process.env.ENVIRONMENT}`
: '.env'
}`
}).parsed
)
})
]
};
};
Route
import React, { Suspense } from 'react';
import Route from './Route';
const Vim = React.lazy(() => import('views/vim'));
export const AuthenticatedRoutes = ({ skipRedirect }) => {
return (
<>
<Route
exact
path='/...'
component={component}
/>
<Route
skipRedirect={skipRedirect}
isPrivate
exact
path='/vim'
component={
<Suspense fallback={<div>Loading...</div>}>
<Vim />
</Suspense>
}
/>
<Route
exact
path='/...'
component={component}
/>
</>
);
};
Page Component
import React from 'react';
import ModuleLoader from '../../components/ModuleLoader';
import { FallbackLoading } from '../../components/FallbackLoading';
import { VimPageWrapper } from './VimPageWrapper';
const Vim = () => {
return (
<ModuleLoader fallback={<FallbackLoading />}>
<VimPageWrapper />
</ModuleLoader>
);
};
export default Vim;
Consuming the MFE
import React from 'react';
import ModuleLoader from 'components/ModuleLoader';
import { FallbackLoading } from 'components/FallbackLoading';
const VimPage = React.lazy(() => import('connect_vim_front/vim-page'));
const Wrapper = React.lazy(() => import('connect_vim_front/Wrapper'));
export const VimPageWrapper = () => {
return (
<ModuleLoader fallback={<FallbackLoading />}>
<Wrapper>
<VimPage />
</Wrapper>
</ModuleLoader>
);
};
Bundle(remoteEntry) loaded even not accessing the route insert the description of the image here
ModuleLoader
import React, { Suspense } from 'react';
import { FallbackError } from '../FallbackError';
class ModuleLoader extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
render() {
const { fallback, children } = this.props;
const { hasError } = this.state;
if (hasError) {
return <FallbackError />;
}
return <Suspense fallback={fallback}>{children}</Suspense>;
}
}
export default ModuleLoader;
I have an app that uses react-router-dom and I have a a basic setup like so:
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import { Box, Flex } from '#chakra-ui/react';
import CodeEntry from './pages/CodeEntry';
import Register from './pages/Register';
// import Login from './pages/Login';
import { useUI } from '../state/context/UIContext';
import { GlobalStyle } from '../styles/GlobalStyles';
import Header from './Header';
import Footer from './Footer';
import ErrorMessage from '../components/ErrorMessage';
import routes from '../config/routes';
const App = () => {
const {
state: { errorMessage },
} = useUI();
return (
<Router>
<GlobalStyle />
<Flex flexDir="column" justifyContent="space-between" minH="100vh">
<Box>
<Header />
{errorMessage.length > 0 && <ErrorMessage message={errorMessage} />}
<Switch>
<Route exact path={routes.APP.REGISTER}>
<Register />
</Route>
<Route exact path={routes.APP.DASHBOARD}>
<>Dashboard</>
</Route>
<Route exact path={routes.APP.HOME}>
<CodeEntry />
</Route>
<Route exact path={routes.APP.LOGIN}>
<>Login</>
</Route>
</Switch>
</Box>
<Box>
<Footer />
</Box>
</Flex>
</Router>
);
};
export default App;
When I run my app locally with npm run dev it uses the following command to spin up a local server:
webpack serve --config webpack.dev.js
the webpack.dev.js file looks like so:
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const path = require('path');
const Dotenv = require('dotenv-webpack');
const plugins = [];
//if (process.env.CI !== 'true') plugins.push(new Dotenv({ systemvars: true, path: path.resolve(__dirname, '.env') }));
module.exports = merge(common, {
mode: 'development',
devServer: {
host: 'localhost',
port: 3000,
historyApiFallback: true,
open: true,
},
infrastructureLogging: {
level: 'error',
},
stats: 'none',
output: {
publicPath: '/',
},
plugins,
});
and the webpack.common.js like so:
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const path = require('path');
require('babel-polyfill');
module.exports = {
entry: {
main: ['babel-polyfill', './src/index.tsx'],
},
devtool: 'source-map',
output: {
filename: '[name].[fullhash].js',
path: path.resolve('./dist'),
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: 'ts-loader',
},
{
test: /\.js$/,
exclude: [path.resolve(__dirname, 'node_modules')],
use: [{ loader: 'babel-loader' }],
},
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
outputPath: 'assets/img/',
},
},
],
},
{
test: /\.(woff(2)?|ttf|eot|otf)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'assets/fonts/',
},
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebPackPlugin({
template: 'index.html',
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['dist'],
}),
new webpack.DefinePlugin({
__REACT_DEVTOOLS_GLOBAL_HOOK__: '({ isDisabled: true })',
}),
],
};
Everything in dev works as it should but when I run a build for production non of my routes apart from the root route ('/') work. Here is how I run a production build:
npm run build && webpack --config webpack.prod.js
and here is how I serve that build locally using the npm package serve:
serve dist --no-clipboard --listen ${PORT:-3000}"
My webpack.prod.js file is quite simple and adopts a lot of the webpack config from the webpack.common.js config file. Here is my prod config:
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
//
module.exports = merge(common, {
mode: 'production',
});
I have tried adding a <Link> component like so:
<Link to='/register'>
The link works fine when I click on it in prod as well as dev, it is just when I navigate directly to the page where I get a 404
Solution was simple, in the end it was an issue with the serve package. All I had to do was a a -s flag to the following command:
serve -s dist --no-clipboard --listen ${PORT:-3000}"
I have this app which I'm rendering on the server side. Everything was working fine until I tried to add Material UI to it.
My directory structure is this:
app/
build/ * This is created by webpack
server_bundle.js
public/
client_bundle.js
fonts/
images/
src/
client/
Client.tsx
server/
server.tsx
shared/
App.tsx
routes.tsx
webpack.config.js
And here are my files content:
webpack.config.js
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
target: 'node',
entry: {
server: path.resolve(__dirname, 'src/server/server.tsx'),
"public/client": path.resolve(__dirname, 'src/client/client.tsx')
},
output: {
filename: '[name]_bundle.js',
path: path.resolve(__dirname, 'build'),
publicPath: '/build'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
module: {
rules: [{
test: /\.(tsx|ts)?$/,
loader: 'awesome-typescript-loader',
options: {
jsx: 'react'
}
},
{
test: /\.(scss|sass|css)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
]
},
{
test: /\.(ico)$/,
loader: 'file-loader',
options: { outputPath: '/public', publicPath: '/public', name: '[name].[ext]' }
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/,
loader: 'file-loader',
options: { outputPath: '/public/images', publicPath: 'images' }
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: { outputPath: '/public/fonts', publicPath: 'fonts' }
},
]
},
optimization: {
},
plugins: [
new MiniCssExtractPlugin({
filename: 'public/styles_bundle.css',
chunkFilename: "public/styles/[id].css"
})
]
}
server.tsx
import * as express from "express";
import * as bodyParser from "body-parser";
import * as React from "react";
import * as ReactDOMServer from "react-dom/server";
import {StaticRouter} from "react-router";
import { matchPath } from "react-router-dom";
import {Helmet} from "react-helmet";
import App from "../shared/App";
import routes from '../shared/routes';
const app = express();
const PORT = process.env.PORT || 3000;
app.use(bodyParser.urlencoded());
app.use(bodyParser.json());
app.use(express.static("build/public"));
app.get('*', (req, res, next) => {
const activeRoute = routes.find(route => !!matchPath(req.url, route)) || {path: "/"};
const now = new Date();
console.log(`GET ${now} - ${req.url}`);
const context = {}
const content = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
const helmet = Helmet.renderStatic();
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
${helmet.title.toString()}
${helmet.meta.toString()}
<link rel="stylesheet" href="styles_bundle.css">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
</head>
<body>
<div id="root" style="overflow-x: hidden; width: 100%; margin: 0;">${content}</div>
<script src="client_bundle.js"></script>
</body>
</html>
`;
res.send(html);
});
app.listen(PORT, () => {
console.log(`App is running on port ${PORT}`)
})
Client.tsx
import * as React from "react";
import * as ReactDOM from 'react-dom';
import { BrowserRouter } from "react-router-dom";
import App from "../shared/App";
// Because it's already been rendered, we only need to hydrate event
// handlers and wire things up.
ReactDOM.hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.querySelector("#root")
);
App.tsx
import * as React from 'react';
import routes from "../shared/routes";
import { Helmet } from 'react-helmet';
import { Switch, Route } from "react-router";
import 'typeface-roboto';
class App extends React.Component {
render() {
return (
<React.Fragment>
<Switch>
{routes.map(({path, exact, component: C}) => {
return <Route
path={path}
exact={exact}
render={(props) => <C {...props}/> }
/>
})}
</Switch>
</React.Fragment>
)
}
}
export default App;
And finally, routes.tsx
import * as React from 'react';
import { Button } from '#material-ui/core';
const routes = [
{
name: "Home",
exact: true,
path: "/",
component: (props:any) => {return (
<Button variant="contained" color="primary">
Hello World
</Button>
)}
}
];
export default routes;
I get this error in my browser console and obviously no material ui styles whatsoever:
client_bundle.js:44 Uncaught ReferenceError: global is not defined
at Object.<anonymous> (client_bundle.js:44)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:1)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:17)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:17)
at n (client_bundle.js:1)
at Object.<anonymous> (client_bundle.js:36)
at n (client_bundle.js:1)
That part of the client_bundle.js looks like this:
... __esModule",{value:!0});global.CSS;t.default=function(e){return e}} ...
What do you think might be happenning here??
try this workaround in your
plugins: [
new webpack.DefinePlugin({
'global': {} // webpack workaround
}),
new MiniCssExtractPlugin({
filename: 'public/styles_bundle.css',
chunkFilename: "public/styles/[id].css"
})
]
I'm developing a project using React/Redux and Node.js.
I added react-router-dom as a dependency into my project and configured the router like this:
import ...
const Router = () => (
<main>
<Switch>
<Route exact path='/' component={components.main}/>
<Route path='/caseDetail/:id' component={components.caseDetail}/>
<Route component={components.notFound}/>
</Switch>
</main>
)
export default Router
And setup my webpack like this
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const merge = require('webpack-merge')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const env = require('./src/env.js')
const TARGET = process.env.npm_lifecycle_event
process.env.BABEL_ENV = TARGET
const PATHS = {
app: path.join(__dirname, 'src'),
build: path.join(__dirname, 'build'),
assets: path.join(__dirname, 'assets')
}
const common = {
entry: [PATHS.app],
module: {
rules: [
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
include: PATHS.app,
loaders: ['babel-loader']
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { modules: true } }],
include: /flexboxgrid/
},
{
test: /\.scss$/,
exclude: /flexboxgrid/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader', options: { modules: true } },
'sass-loader'
]
},
{
test: /\.jpe?g$|\.gif$|\.png$/i,
loader: 'url-loader?name=[name].[ext]'
},
{
test: /\.otf$|\.eot$|\.svg$|\.ttf|\.woff|\.woff2$/,
loader: 'url-loader?name=[name].[ext]'
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
modules: ['node_modules', path.resolve(__dirname, './node_modules')],
mainFields: ['browser', 'web', 'browserify', 'main', 'style']
}
}
if (TARGET === 'start' || !TARGET) {
module.exports = merge(common, {
module: {
rules: [
{
test: /\.jsx?$/,
use: ['source-map-loader'],
enforce: 'pre'
}
]
},
devtool: 'inline-source-map',
devServer: {
contentBase: PATHS.build,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
stats: 'errors-only',
https: true,
host: env.host,
port: env.port,
overlay: {
errors: true
},
watchOptions: {
watch: true
}
},
plugins: [
new MiniCssExtractPlugin({ filename: 'assets/style.css' }),
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: PATHS.app + '/index.html',
inject: 'body'
})
],
output: {
path: PATHS.build,
filename: 'bundle.js'
}
})
}
if (TARGET === 'production') {
module.exports = merge(common, {
plugins: [
new MiniCssExtractPlugin({ filename: 'style.css' }),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: "'production'"
}
})
],
output: {
path: '/build',
filename: 'bundle.js'
}
})
}
My problem is
When I call this route /caseDetail/1 it works by using Link:
<Link to={{ pathname: `/caseDetail/` + caseStudy.id }}>
BUT, if I call directly by the browser, like https://localhost:3000/caseDetail/1
It fails, I get this message on console
Refused to apply style from 'https://localhost:3000/caseDetail/assets/style.css' because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checking is enabled.
0:12 GET https://localhost:3000/caseDetail/bundle.js net::ERR_ABORTED 404
0:1 Refused to execute script from 'https://localhost:3000/caseDetail/bundle.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
SOLVED
How to fix. Thanks to #soroush-chehresa
I added into my router file, the BrowserRouter like this:
import React from 'react'
import { Switch, Route, BrowserRouter } from 'react-router-dom'
import { components } from './loader'
const Router = () => (
<main>
<BrowserRouter>
<Switch>
<Route exact path='/' component={components.main}/>
<Route exact path='/caseDetail' component={components.caseDetail}/>
<Route path='/caseDetail/:id' component={components.caseDetail}/>
<Route component={components.notFound}/>
</Switch>
</BrowserRouter>
</main>
)
export default Router
And also added into my webpack.config.js on output
publicPath: '/'
If you are using react-router-redux wrap Router with ConnectedRouter:
import { ConnectedRouter } from 'react-router-redux';
import { createBrowserHistory } from 'history';
const Router = () => (
<main>
<ConnectedRouter history={createBrowserHistory()}>
<Switch>
<Route exact path='/' component={components.main}/>
<Route path='/caseDetail/:id' component= {components.caseDetail}/>
<Route component={components.notFound}/>
</Switch>
</ConnectedRouter>
</main>
);
Otherwise if you are using react-router-dom wrap Router with BrowserRouter:
import { BrowserRouter } from 'react-router-dom';
const Router = () => (
<main>
<BrowserRouter>
<Switch>
<Route exact path='/' component={components.main}/>
<Route path='/caseDetail/:id' component={components.caseDetail}/>
<Route component={components.notFound}/>
</Switch>
</BrowserRouter>
</main>
);
I am developing in a windows environment for the first time (coming from OS).
I have built the basic foundation for a react app, and webpack builds without errors, but only the raw HTML renders. I.e., the ReactDOM process seems to fail or something because my app component doesn't render at all. Note that I leveraged code from an app I built in OS, wondering if that has something to do with it.
See code below. Thank you for having a look.
First my webpack.config.js file:
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer = require('autoprefixer');
const SRC_DIR = path.join(__dirname, '/client/src');
const DIST_DIR = path.join(__dirname, '/client/dist');
module.exports = {
entry: `${SRC_DIR}\\index.js`,
output: {
path: path.resolve(__dirname, 'client/dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?/,
include: SRC_DIR,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015'],
plugins: ['syntax-dynamic-import'],
},
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
include: SRC_DIR,
},
],
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},
}),
new ExtractTextPlugin("styles.css"),
// ,
// new UglifyJSPlugin(),
],
};
Next my html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="shortcut icon" href="https://orig00.deviantart.net/15e4/f/2011/116/f/4/color_wheel_dock_icon_by_andybaumgar-d3ezjgc.png">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">
<title>SysAdmin Microservices</title>
</head>
<body>
<h1>Node Microservices Server Documentation</h1>
<div id="root"></div>
</body>
</html>
My index.js file with the ReactDOM.render call:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './containers/App.jsx';
ReactDOM.render( <App />, document.getElementById('root'));
Last of all my App.js file:
import React from 'react';
class App extends React {
render() {
console.log('app render has been invoked <-- this never logs to the console ');
return (
<h1>This is the text that does not render in the browser.</h1>
)
}
}
export default App;
You need to have your bundle.js referenced from the index page, else it won't load any of your JS. Will vary based on your folder structure, but something along the lines of this should work:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>
Or you could use a Webpack plugin like html-webpack-plugin to inject your bundled JS as a part of your build process.
You can add the script to your bundle manually or use html-webpack-plugin.
This plugin will handle inserting scripts/style to the index html (and more) automatically.
Steps:
Install the plugin: npm install --save-dev html-webpack-plugin
Require it in webpack config: const HtmlWebpackPlugin = require('html-webpack-plugin')
Add the plugin to the plugin config:
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
},
}),
new ExtractTextPlugin("styles.css"),
// ,
// new UglifyJSPlugin(),
]