aws-amplify / amplify-cli

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development.
Apache License 2.0
2.81k stars 821 forks source link

how to share code in client and nodejs lambda? #6414

Closed cyrfer closed 3 years ago

cyrfer commented 3 years ago

Which Category is your question related to? Function, React client

Amplify CLI Version 4.40.1

What AWS Services are you utilizing? AppSync, Lambda, Cognito, S3

Provide additional details e.g. code snippets I would like to develop a package within the Amplify project that contains some functions and schema files required by both my CreateReactApp client and my backend in a Nodejs Lambda function for AppSync.

Are there any guides about this?

amcdnl commented 3 years ago

I use the amplify codegen in my UI and point it to the API project to get the schema/types.

cyrfer commented 3 years ago

@amcdnl thanks but I think we're talking about different topics. I'm using GraphQL for my API but the code I'm trying to share with my Lambda & front-end is a Json Schema file as well as other JS functions.

cyrfer commented 3 years ago

I was able to make some progress, but I'm hindered by the fact that amplify push is not honoring the build hook.

My function/foo/src/package.json file has a npm run script called amplify:foo but it does not get invoked when I call amplify push as advertised in Example: Transpiling ES6 code with Babel. 🐞 BUG ALERT!

My strategy to share code between the react client and the backend lambda in the same git repo has been to leverage local file packages. Unfortunately, this results in a function/foo/dist/latest-build.zip that is missing the relative modules. To fix that, I'm using webpack to bundle my lambda, which resolves the relative modules at build time, producing self-contained source code for amplify to deploy.

For example, given a project with the following directory structure:

amplify/backend/function/foo/
  src/package.json
  lib/
    package.json
    webpack.config.js
package.json
src/react-files
packages/
  bar/package.json

I can setup the relative path dependencies with:

# for react client
npm i -S packages/bar
# for the lambda
cd amplify/backend/function/foo/lib && npm i -S ../../../../../packages/bar

Because amplify v 4.41.2 is not triggering the npm run script, I will need to setup a commit hook or something. For now I'm manually running:

cd amplify/backend/function/foo/src && npm run amplify:foo

...which simply runs

"scripts": {
  "amplify:foo": "cd ../lib && npm run build
}

All my source code is in the function/foo/lib directory. You can see below that webpack will write out function/foo/src/index.js. I commit the bundled src/index.js file so that it always gets packaged into a zip file by amplify push.

// function/foo/lib/webpack.config.js
const path = require('path');

module.exports = {
  mode: 'production',
  entry: './index.js',
  target: 'node',
  output: {
    filename: 'index.js',
    path: path.resolve(__dirname, '../src'),
    libraryTarget: 'commonjs',
  },
};
wderezin commented 3 years ago

The amplify:foo goes in the project root package.json not in the function function/foo/src/package.json

Also, you can not sym link files into the function as the amplify build process will not pick up the files when it zips the ./src directory. You either have to copy the files or hard link the files.

cyrfer commented 3 years ago

@wderezin thanks for the tip about using the project root package.json for the build commands. I see the documentation says the same.

I am trying to build my local package when the lambda is built. My lambda imports the resulting package. I don't see any obvious feedback in the terminal about commands executed at build time. If I'm using the right package.json and the right script alias, should I expect to see output in the terminal from my build commands?

Here is a snippet from my top-level package.json

"scripts": {
    "build-package": "cd packages/cool-stuff && npm run build",
    "amplify:foo": "npm run build-package"
}
cyrfer commented 3 years ago

The documented solutions are working.

I created subfolders for local packages, with lambda function packages and my react client referencing the local packages using local file paths, and bundling lambda function code with top-level scripts.

amplify will take whatever is bundled in the amplify/backend/function/foo/src directory. I keep my ES6/TS source code in an adjacent folder. When developing locally, I use a watcher to run the build scripts for the function or local package.

Im also excited to be able to build using webpack+typescript to get typescript support with lambda functions in amplify, running locally.

I think this ticket can be closed using the existing features!

github-actions[bot] commented 3 years ago

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels for those types of questions.