2024 06 30 Integrating shared constants between parent app and CDK project - bizkite-co/handterm GitHub Wiki


original file name: Codeium Chat - 7HNg2SpEKP3NYdGGW8DYVw4Fb60HuaRg.md summary: The chat discussion revolved around integrating shared string constants between a parent Vite Yarn React app and a subdirectory AWS CDK infrastructure project. The user faced errors related to module resolution and TypeScript compilation strategies due to differences in module systems between the projects. Suggestions were provided to troubleshoot the issues, such as checking module resolution strategies, verifying file paths, and ensuring consistent TypeScript compilation.

The user implemented a workaround by copying the endpoints.ts file from the parent project to the CDK project, but expressed concerns about code duplication and accidental updates. Recommendations were given to automate the syncing process more safely using version control hooks, read-only access in the CDK project, centralizing shared code with symlinks or a shared library, and utilizing a CI pipeline for automated resource copying. These strategies aimed to improve the development workflow and reduce the risk of errors while maintaining a single source of truth for shared code. date: 2024-06-30T11:29

Codeium Chat Conversation

Note: This is purely the output of the chat conversation and does not contain any raw data, codebase snippets, etc. used to generate the output.

User at 11:29 am, Jun 30, 2024

I have create this file in my parent Vite Yarn React app:

// shared/endpoints.ts

export const ENDPOINTS = {
  aws: {
    cognito: {
      url: 'https://cognito-idp.us-east-1.amazonaws.com',
    },
    s3: {
      url: 'https://s3.amazonaws.com',
      bucketName: 'handterm-history',
    },
  },
  api: {
    SignUp: '/signUp',
    GetLog: '/getLog',
    SaveLog: '/saveLog',
    SignIn: '/signIn',
    SignOut: '/signOut',
    ChangePassword: '/changePassword',
    TokenHandler: '/tokenHandler',
    RefreshSession: '/refreshSession',
    CheckSession: '/checkSession',
    GetUser: '/getUser',
  }

} as const

Because I want to standardize endpoint strings in the parent app and in a subdirectory AWS CDK infrastructure project in the cdk/.

I'm getting some errors, though, from the different TypeScript compilation strategies.

My parent app has this tsconfig.json

// tsconfig.json

{
 "compilerOptions": {
  "baseUrl": "./",
  "target": "ES2020",
  "useDefineForClassFields": true,
  "lib": ["ES2020", "DOM", "DOM.Iterable"],
  "module": "ESNext",
  "skipLibCheck": true,
  "outDir": "./dist",

  /* Bundler mode */
  "moduleResolution": "bundler",
  "allowImportingTsExtensions": true,
  "resolveJsonModule": true,
  "isolatedModules": true,
  "noEmit": true,
  "jsx": "react-jsx",

  /* Linting */
  "strict": true,
  "noUnusedLocals": true,
  "noUnusedParameters": true,
  "noFallthroughCasesInSwitch": true
 },
 "include": [
  "./src",
  "./shared",
  "./src/types/elements.d.ts",
 ],
 "references": [{ "path": "./tsconfig.node.json" }]
}

But now I am getting this:


useAuth.ts:3  
Uncaught (in promise) SyntaxError: The requested module '/shared/endpoints.js' does not provide an export named 'ENDPOINTS' (at useAuth.ts:3:10)

From trying to do this:

// src/lib/useAuth.ts

import { useState, useEffect } from 'react';
import axios from 'axios';
import { ENDPOINTS } from '../../shared/endpoints';

I need your help figuring out the best way to integrate shared string constants between these to projects.

Here is the tsconfig.json for the cdk/ project

// cdk/tsconfig.json

{
 "compilerOptions": {
  "target": "ES2020",
  "module": "CommonJS",
  "esModuleInterop": true,
  "outDir": "cdk.out",
  "lib": [
   "es2020",
   "dom"
  ],
  "declaration": true,
  "strict": true,
  "noImplicitAny": true,
  "strictNullChecks": true,
  "noImplicitThis": true,
  "alwaysStrict": true,
  "noUnusedLocals": false,
  "noUnusedParameters": false,
  "noImplicitReturns": true,
  "noFallthroughCasesInSwitch": false,
  "inlineSourceMap": true,
  "inlineSources": true,
  "experimentalDecorators": true,
  "strictPropertyInitialization": false,
  "typeRoots": [
   "./node_modules/@types"
  ]
 },
 "include": [
  "../shared/**/*",
 ],
 "exclude": [
  "node_modules",
  "cdk.out"
 ]
}

Codeium at 11:30 am, Jun 30, 2024

The error you're encountering, SyntaxError: The requested module '/shared/endpoints.js' does not provide an export named 'ENDPOINTS', is likely due to the way modules are resolved and the differences in module systems between your Vite/React app (ESNext modules) and your cdk/ project (CommonJS modules). Here are some steps to troubleshoot and potentially resolve this issue:

1. Check the Module Resolution Strategy

Your Vite/React app and CDK project use different module systems. Your Vite app uses ES modules ("module": "ESNext"), while your CDK project uses CommonJS ("module": "CommonJS"). Ensure that files are correctly transpiled and that you're using the appropriate import/export syntax for each project.

2. Verify the File Path

The error suggests that the module resolution might not be working as expected. Double-check the relative path you're using in the import statement. Since you're using TypeScript, you might need to compile your TypeScript files to JavaScript before they can be used, depending on your setup.

3. Consistent Use of TypeScript

If you're using TypeScript across both projects, make sure that the TypeScript files are compiled correctly in each context. Your Vite project is set up not to emit output ("noEmit": true in your parent app's tsconfig.json), which could be part of the problem if you're trying to import TypeScript files directly without a build step that compiles them to JavaScript.

4. Adjust TypeScript Configuration for Shared Code

Since your cdk/tsconfig.json includes the ../shared/**/* folder, it suggests you want to share code between the CDK and Vite projects. Ensure that the shared code is compiled in a way compatible with both projects. You might need an additional build step for the shared code or adjust your TypeScript configuration to output compatible JavaScript code.

5. Use a Symlink for Local Development

For local development, consider using a symbolic link (symlink) to include the shared directory in your CDK project. This way, you can work on your shared codebase without constantly copying files back and forth. Be cautious with symlinks and your build tools, as not all tools follow symlinks correctly by default.

Potential Solution

Given the error and your setup, one approach could be to ensure that the shared code is compiled to JavaScript with the appropriate module syntax (CommonJS for your CDK project, ES modules for your Vite project) and then imported correctly. You might need a separate tsconfig.json or a build step for the shared directory to output the files in a format that works for both projects.

Example Build Step for Shared Code

Consider adding a script in your package.json to compile the shared code with TypeScript compiler (tsc) before running your projects:

"scripts": {
  "build-shared": "tsc --project ./path/to/shared/tsconfig.json",
  "start": "npm run build-shared && vite",
  "build-cdk": "npm run build-shared && cd cdk && npm run build"
}

This script assumes you have a tsconfig.json in your shared directory configured to output JavaScript code compatible with both projects. Adjust the paths and commands according to your project structure.

Debugging Steps

  • Ensure that the TypeScript compilation of shared code is successful and outputs JavaScript files.
  • Check the compiled code to verify the export of ENDPOINTS matches the import syntax used in your useAuth.ts file.
  • Consider adjusting the baseUrl and paths in your tsconfig.json files to simplify module resolution.

User at 11:59 am, Jun 30, 2024

In my cdk/package.json I have this:

 "scripts": {
  "build": "tsc",
  "deploy": "yarn build && cdk deploy --region=us-east-1 --profile mark",
  "watch": "tsc -w",
  "test": "jest",
  "cdk": "cdk"
 },

I would like to a "cdk-build" like the one you described, and a "cdk-ceploy" to my parent package.json.

How can I do that?

Keep in mind that I am using Yarn, not NPM.


Codeium at 11:59 am, Jun 30, 2024

To add a cdk-build and a cdk-deploy script to your parent package.json that leverages Yarn instead of NPM, you'll follow a similar approach to the one described but with Yarn commands. Here's how you can do it:

  1. cdk-build: This script will navigate into the cdk/ directory, run the TypeScript compiler to build your CDK project, and then navigate back to the parent directory.

  2. cdk-deploy: This script will depend on the cdk-build script to ensure the CDK project is built before deploying. After building, it will deploy using the CDK deploy command with your specified options.

Here's how you can add these scripts to your parent package.json:

"scripts": {
  "cdk-build": "cd cdk && yarn build && cd ..",
  "cdk-deploy": "yarn cdk-build && cd cdk && yarn deploy"
}

Explanation:

  • cd cdk && yarn build && cd ..: This changes the directory to cdk/, runs the build script defined in cdk/package.json (which is "build": "tsc" as per your configuration), and then returns to the parent directory.

  • yarn cdk-build && cd cdk && yarn deploy: First, this runs the cdk-build script defined above. If the build succeeds, it changes the directory to cdk/ and runs the deploy script defined in cdk/package.json.

Notes:

  • Yarn vs. NPM: The commands use yarn instead of npm run for running scripts as you mentioned your project uses Yarn. Yarn and NPM are both package managers, but they use slightly different command syntax for executing scripts.

  • Deployment Profile: The deployment script includes --profile mark as per your setup. Ensure the AWS CLI is configured with this profile for deployment.

  • Returning to the Parent Directory: It's important to navigate back to the parent directory (cd ..) after the build or deploy script is executed in the CDK directory to ensure any subsequent commands are run from the correct location.

Additional Tip:

If your cdk directory is deeply nested or you find yourself frequently running these scripts, consider using more advanced shell scripting techniques or tools like lerna for managing multi-package repositories. This can simplify command execution and improve project structure management.


User at 1:27 pm, Jun 30, 2024

I had to do this for the shared/endpoints.ts as a workaround.

It simply copies the parent endpoints.ts into the child.

This is not very good, because I could accidently make updates to the target and it's code duplication, but it is currently working.

 "scripts": {
  "cpCdk": "cp shared/endpoints.ts cdk/cdkshared/",
  "dev": "vite",
  "build": "vite build",
  "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
  "preview": "vite preview",
  "build-shared": "vite build --ssr",
  "cdk-build": "yarn cpCdk && cd cdk && yarn build && cd ..",
  "cdk-deploy": "yarn cdk-build && cd cdk && yarn deploy && cd .."
 },

Codeium at 1:27 pm, Jun 30, 2024

Given your current workaround for the shared/endpoints.ts file by copying it from the parent project to the child CDK project, I understand your concern about potential code duplication and the risk of accidental updates in the target directory. To mitigate these concerns while maintaining the current working state, consider implementing a more automated or safer approach to synchronize changes between the shared code and its uses. Here are a couple of suggestions:

Automate the Syncing Process More Safely

  1. Version Control Hooks: Use Git hooks to automate the copy process before certain actions. For instance, a pre-commit hook could ensure endpoints.ts is copied and up to date in the cdk project before each commit. However, this requires discipline to ensure changes are committed regularly.

  2. Read-Only Access in CDK: Make the copied endpoints.ts in the CDK project read-only. This can act as a deterrent against accidental modifications since any attempt to modify the file directly would result in an error.

Improve the Development Workflow

  1. Centralize Shared Code: Instead of copying files, consider creating a symlink to shared/endpoints.ts in your CDK project. This would keep a single source of truth and immediately reflect changes across projects. However, symlinks can introduce their own set of issues, especially with different operating systems and IDEs.

  2. Create a Shared Library: Package your shared code (like endpoints.ts) into a separate library that both your parent app and CDK project can import as a dependency. This approach is cleaner but requires setting up a private package repository if you do not want the package to be public or using relative paths with file references in your package.json files.

"dependencies": {
  "shared-endpoints": "file:../path-to-shared-package"
}

This method allows you to use standard package management practices to share code between projects, with the added benefit of version control for your shared code.

Continuous Integration (CI) Pipeline

If you're using a CI/CD pipeline, you can include steps in your pipeline to automate the copying of shared resources. This ensures that the latest version of the shared file is always used during builds or deployments without manually running the copy script.

Final Thoughts

While the copy script (cpCdk) works, these suggestions aim to streamline your development process and reduce the risk of errors. The best solution depends on your project's complexity, the size of your team, and how frequently shared/endpoints.ts changes.

⚠️ **GitHub.com Fallback** ⚠️