GitHub - fc-micro-frontends/career-up at step6

➜ pnpm --filter @career-up/shell add dotenv-webpack -D
// career-up/apps/shell/webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
**const Dotenv = require("dotenv-webpack");**
const deps = require("./package.json").dependencies;
module.exports = (_, argv) => ({
output: {
publicPath: "<http://localhost:3000/>",
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 3000,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
],
},
plugins: [
**new Dotenv(),**
new ModuleFederationPlugin({
name: "shell",
filename: "remoteEntry.js",
remotes: {
posting: "posting@<http://localhost:3001/remoteEntry.js>",
},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"@career-up/shell-router": {
singleton: true,
},
"@career-up/ui-kit": {
singleton: true,
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
});
REACT_APP_AUTH0_DOMAIN=dev-vcrmf0xuep020tri.us.auth0.com
REACT_APP_AUTH0_CLIENT_ID=27LLb4I9cIjiiQNSjbNIX9sQM1KECUfk
REACT_APP_AUTH0_CALLBACK_URL=http://localhost:3000
➜ pnpm --filter @career-up/shell add @auth0/auth0-react
// career-up/apps/shell/src/components/auth0-provider-with-navigator.tsx
import { type AppState, Auth0Provider } from "@auth0/auth0-react";
import React from "react";
import { useNavigate } from "react-router-dom";
export const Auth0ProviderWithNavigator: React.FC<React.PropsWithChildren> = ({
children,
}) => {
const navigate = useNavigate();
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
const redirectUri = process.env.REACT_APP_AUTH0_CALLBACK_URL;
const onRedirectCallback = (appState?: AppState) => {
navigate(appState?.returnTo || window.location.pathname);
};
if (!(domain && clientId && redirectUri)) {
return null;
}
return (
<Auth0Provider
domain={domain}
clientId={clientId}
authorizationParams={{
redirect_uri: redirectUri,
}}
onRedirectCallback={onRedirectCallback}
>
{children}
</Auth0Provider>
);
};
➜ pnpm --filter @career-up/shell add @types/node -D
➜ pnpm --filter @career-up/shell add @babel/runtime -D
// career-up/apps/shell/src/router.tsx
import React, { Suspense } from "react";
import {
createBrowserRouter,
Navigate,
RouterProvider,
} from "react-router-dom";
import Layout from "./components/layout";
import { appPostingBasename } from "./constants/prefix";
**import { Auth0ProviderWithNavigator } from "./components/auth0-provider-with-navigator";**
const AppPostingLazy = React.lazy(() => import("./components/app-posting"));
const browserRouter = createBrowserRouter([
{
path: "/",
element: (
**<Auth0ProviderWithNavigator>**
<Layout />
**</Auth0ProviderWithNavigator>**
),
errorElement: <div>404 Not Found</div>,
children: [
{
index: true,
element: <Navigate to={`${appPostingBasename}`} />,
},
{
path: `${appPostingBasename}/*`,
element: (
<Suspense fallback="Loading Posting...">
<AppPostingLazy />
</Suspense>
),
},
],
},
]);
export default function Router() {
return <RouterProvider router={browserRouter} />;
}
// career-up/apps/shell/src/components/layout.tsx
import React from "react";
import { Link, NavLink, Outlet } from "react-router-dom";
import {
appEduBasename,
appJobBasename,
appNetworkBasename,
appPostingBasename,
} from "../constants/prefix";
import { **Button,** Icon } from "@career-up/ui-kit";
**import { useAuth0 } from "@auth0/auth0-react";**
const Layout = () => {
**const { loginWithRedirect, logout, isAuthenticated } = useAuth0();
const handleLogin = async () => {
await loginWithRedirect({
appState: {
returnTo: "/",
},
});
};
const handleLogout = async () => {
await logout({
logoutParams: {
returnTo: window.location.origin,
},
});
};**
return (
<div>
<header className="global-nav">
<div className="global-nav-content">
<Link className="global-nav-logo" to="/">
<svg
data-v-62b4fdfc=""
width="30"
height="30"
viewBox="0 0 76 76"
fill="none"
xmlns="<http://www.w3.org/2000/svg>"
>
<g data-v-62b4fdfc="" clipPath="url(#clip0_2879_347)">
<path
data-v-62b4fdfc=""
d="M75.461 37.722a.219.219 0 00.327-.19C75.575 16.805 58.702.069 37.928.069a37.617 37.617 0 00-18.58 4.88.22.22 0 000 .38L75.46 37.722zM5.328 19.347a.22.22 0 00-.38 0 37.617 37.617 0 00-4.88 18.58c0 20.775 16.737 37.64 37.458 37.86a.219.219 0 00.19-.326L5.327 19.347zM12.326 12.47l35.666 61.776a.22.22 0 00.25.099c12.616-3.568 22.543-13.495 26.11-26.11a.22.22 0 00-.098-.25L12.47 12.324c-.09-.052-.197.054-.144.145z"
fill="#FC1C49"
></path>
</g>
<defs data-v-62b4fdfc="">
<clipPath data-v-62b4fdfc="" id="clip0_2879_347">
<path
data-v-62b4fdfc=""
fill="#fff"
d="M0 0h500v75.901H0z"
></path>
</clipPath>
</defs>
</svg>
<span>Career Up</span>
</Link>
**{!isAuthenticated && (
<div style={{ marginLeft: 20 }}>
<Button onClick={handleLogin}>Login</Button>
</div>
)}
{isAuthenticated && (
<div style={{ marginLeft: 20 }}>
<Button onClick={handleLogout}>Logout</Button>
</div>
)}**
<nav className="global-nav-nav">
<ul className="global-nav-items">
<li className="global-nav-item">
<NavLink
className="global-nav-link"
to={`${appPostingBasename}`}
>
<Icon.Home />
<span className="global-nav-link-text">홈</span>
</NavLink>
</li>
<li className="global-nav-item">
<NavLink
className="global-nav-link"
to={`${appNetworkBasename}`}
>
<Icon.UserFriends />
<span className="global-nav-link-text">인맥</span>
</NavLink>
</li>
<li className="global-nav-item">
<NavLink className="global-nav-link" to={`${appEduBasename}`}>
<Icon.LaptopCode />
<span className="global-nav-link-text">교육</span>
</NavLink>
</li>
<li className="global-nav-item">
<NavLink className="global-nav-link" to={`${appJobBasename}`}>
<Icon.Briefcase />
<span className="global-nav-link-text">채용공고</span>
</NavLink>
</li>
</ul>
</nav>
</div>
</header>
**<div className="global-container">{isAuthenticated && <Outlet />}</div>**
</div>
);
};
export default Layout;
➜ pnpm dev