이어서 할 곳

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

REACT_APP_AUTH0_DOMAIN=dev-vcrmf0xuep020tri.us.auth0.com
REACT_APP_AUTH0_CLIENT_ID=27LLb4I9cIjiiQNSjbNIX9sQM1KECUfk
REACT_APP_AUTH0_CALLBACK_URL=http://localhost:3000
➜ pnpm i

➜ pnpm build

job 에서 프레그먼트 노출하기

// career-up/apps/job/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:3004/>",
  },

  resolve: {
    extensions: [".tsx", ".ts", ".jsx", ".js", ".json"],
  },

  devServer: {
    port: 3004,
    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({
      path: "../../.env",
    }),
    new ModuleFederationPlugin({
      name: "job",
      filename: "remoteEntry.js",
      remotes: {},
      exposes: {
        "./injector": "./src/injector.tsx",
        **"./fragment-recommend-jobs":
          "./src/fragments/recommend-jobs-container.tsx",**
      },
      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",
    }),
  ],
});
// career-up/apps/job/src/fragments/recommend-jobs-container.tsx

import React, { useCallback, useState } from "react";
import RecommendJobs from "../components/recommend-jobs";
import { type JobType } from "../types";
import { useAuth0Client } from "@career-up/shell-router";
import { getJobs } from "../apis";

const RecommendJobsContainer: React.FC = () => {
  const auth0Client = useAuth0Client();
  const [jobs, setJobs] = useState<JobType[]>([]);

  const fetchJobs = useCallback(async () => {
    try {
      const token = await auth0Client.getTokenSilently();
      const jobs = await getJobs(token);
      setJobs(jobs.slice(0, 3));
    } catch (error) {
      alert(error);
    }
  }, [auth0Client]);

  return <RecommendJobs jobs={jobs} fetchJobs={fetchJobs} />;
};

export default RecommendJobsContainer;
// career-up/apps/job/src/components/recommend-jobs.styles.ts

import styled from "@emotion/styled";

export const RecommendJobsWrapper = styled.div`
  .job--recommend-jobs-top {
    display: flex;
    flex-direction: column;
    background-color: white;

    padding: 16px 12px 16px;
    border-radius: 8px 8px 0 0;
    border-bottom: 1px solid rgb(0 0 0 / 0.1);
    gap: 10px;
  }

  .job--recommend-jobs-top-title {
    font-size: 15px;
    font-weight: bold;
    height: 15px;
  }

  .job--recommend-jobs-bottom {
    display: flex;
    flex-direction: column;
    border-radius: 0 0 8px 8px;
    background-color: white;
  }
`;
// career-up/apps/job/src/components/recommend-jobs.tsx

import React, { useEffect } from "react";
import { RecommendJobsWrapper } from "./recommend-jobs.styles";
import { JobType } from "../types";
import RecommendJob from "./recommend-job";

interface RecommendJobsProps {
  jobs: JobType[];
  fetchJobs: () => Promise<void>;
}

const RecommendJobs: React.FC<RecommendJobsProps> = ({ jobs, fetchJobs }) => {
  useEffect(() => {
    fetchJobs();
  }, [fetchJobs]);

  return (
    <RecommendJobsWrapper>
      <div className="job--recommend-jobs-top">
        <span className="job--recommend-jobs-top-title">추천 채용공고</span>
      </div>
      <div className="job--recommend-jobs-bottom">
        {jobs.map((job) => (
          <RecommendJob key={job.id} {...job} />
        ))}
      </div>
    </RecommendJobsWrapper>
  );
};

export default RecommendJobs;
// career-up/apps/job/src/components/recommend-job.styles.ts

import styled from "@emotion/styled";

export const RecommendJobWrapper = styled.div`
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 16px 12px 16px;

  .job--recommend-job-position {
    font-size: 16px;
    font-weight: 600;
    color: rgb(0 0 0 / 0.9);

    width: 100%;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
    word-break: break-all;
  }

  .job--recommend-job-company {
    font-size: 14px;
    color: rgb(0 0 0 / 0.6);
  }

  :hover {
    background-color: rgb(0 0 0 / 0.1);
    cursor: pointer;
  }
`;
// career-up/apps/job/src/components/recommend-job.tsx

import "./recommend-job.styles";

import React from "react";
import { RecommendJobWrapper } from "./recommend-job.styles";
import { useShellNavigate } from "@career-up/shell-router";

interface RecommendJobProps {
  id: number;
  position: string;
  company: string;
}

const RecommendJob: React.FC<RecommendJobProps> = ({
  id,
  position,
  company,
}) => {
  const navigate = useShellNavigate();
  const onClick = () => {
    navigate(`/job/${id}`);
  };
  return (
    <RecommendJobWrapper onClick={onClick}>
      <div className="job--recommend-job-position">{position}</div>
      <div className="job--recommend-job-company">{company}</div>
    </RecommendJobWrapper>
  );
};

export default RecommendJob;
➜ pnpm dev

최종

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