aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.42k stars 2.12k forks source link

How to use amplify-js with plain javascript? #4510

Closed groundswel closed 4 years ago

groundswel commented 4 years ago

Is your feature request related to a problem? Please describe.

The README talks about how to use amplify-js library with nodejs / Vue / React and other complex JavaScript frameworks. Can we also have couple of lines dedicated to how to use amplify with plain old javascript ie without depending on React or anything else?

jkeys-ecg-nmsu commented 4 years ago

Those are view frameworks. Checkout the Auth API and see if that answers your question. You can also take a look at the source for the Amplify components library to see how it uses Auth category internally.

ericclemmons commented 4 years ago

@groundswel That's a good question! Can help me understand an example of something you'd like to be able to accomplish with "plain old JavaScript", or the ideal solution you'd find in our docs?

For example, we released DataStore (https://aws-amplify.github.io/docs/js/datastore) which doesn't have dependencies on React/Vue/etc. The example only has npx create-react-app so that many of our users would be able to see it working, vs. reading console.log output.

groundswel commented 4 years ago

@ericclemmons I would like to achieve creation of a website without react/vue . I know jquery and bootstrap - those are the only two frameworks that are sufficient for my needs. However it seems that though amplify have a JS library , to take advantage of it I need to plan for using react.

ericclemmons commented 4 years ago

@groundswel Do you have a build process (e.g. webpack, parcel, gulp, grunt, etc.), or is the jQuery/Bootstrap code being published as-is? (Any links you have would be helpful!)

groundswel commented 4 years ago

No I dont have a build process and not planning to have one unless needed.

ericclemmons commented 4 years ago

@groundswel Unfortunately, we don't have standalone, single-file builds like jQuery or Bootstrap. (Libraries like Bootstrap & jQuery have been explicitly bundled for consumption via a CDN and a single <script> or <link> tag.)

Currently, Amplify ships with both ES5 & ES6 modules so that application bundlers (e.g. Parcel, Webpack, Rollup) can choose the right bundling strategy based on the users your app is targeting, saving network calls & file-size for users.

Also, Amplify's features like API, Auth, DataStore require using the Amplify CLI to generate models/infrastructure, which quickly becomes unwieldy without a build process.

If there's an Amplify feature that you'd like to take advantage of without going all-in on React/Vue/Angular, let me know and I'll help get you going in the right direction. 🙏

jkeys-ecg-nmsu commented 4 years ago

https://aws-amplify.github.io/amplify-js/api/classes/authclass.html

The view frameworks are 99% handling auth* for you, so you could (per my original suggestion) go take a look at the react/vue/angular code and see how they use Auth category (which of course requires you have a Cognito user pool and/or identity pool.) As an example:

https://github.com/aws-amplify/amplify-js/blob/8d2ba6e85031a7880d2b573e1f68108d22a7de54/packages/aws-amplify-react/src/Auth/SignIn.tsx#L93-L131

You can read the source to see how the components work for other categories, too.

groundswel commented 4 years ago

Also, Amplify's features like API, Auth, DataStore require using the Amplify CLI to generate models/infrastructure, which quickly becomes unwieldy without a build process.

If there's an Amplify feature that you'd like to take advantage of without going all-in on React/Vue/Angular, let me know and I'll help get you going in the right direction. 🙏

@ericclemmons For example I want to have authenticated users to subscribe from available vacation packages. My idea is that I simply will have the static html/js files hosted on S3 website. When users browse to the website the static pages will be pulled by the browser. The login button will take then to Cognito hosted UI for singup/login. Once logged in Cognito will send back the code as parameter to the redirect_url (which is another static html+js from S3). This page will be a dashboard page that will use the code to fetch the JWT token and use the JWT token to talk to appsync to get the list of vacation packages and the subscription status for them. It will then parse the results and display it to the user. The same html+js page will do all the necessary update operations as well on behalf of the user. Hence I just need to find some client side code to interact with Appsync. Is their anything lightweight to use on the client side for this use case?

ericclemmons commented 4 years ago

@groundswel That's an excellent example, thank you!

However, I do think you'll need a build process to bring in the aws-amplify dependency, since it doesn't work as a drop-in <script> tag.

Do you have AppSync setup currently with the vacation packages?

You can use the simpler Amplify's GraphQL client (https://aws-amplify.github.io/docs/js/api#simple-query), or the AppSync SDK for both GraphQL and REST clients without a framework:

Let me know if that helps! With a bundler like https://parceljs.org/, you should be able to write vanilla HTML + JS and successfully import Amplify from 'aws-amplify', add features via the Amplify CLI, and deploy to S3.

groundswel commented 4 years ago

Thanks @ericclemmons for your suggestions. On thinking it through more I do see some clear value add that amplify framework brings in terms of setting up the resolvers for the API calls and other backend things. However I am worried that using it would add a whole lot more to my codebase than I really need.

ericclemmons commented 4 years ago

@groundswel You're spot on: Amplify should be making the backend stuff for you much easier.

The great news is that you can start with the features that make sense without going "all in" on Amplify.

Take Auth, for example. With the Amplify CLI, you can created a hosted UI pretty quickly that users get to with the click of a link. You'd be able to get the current user with a few lines of code:

https://aws-amplify.github.io/docs/js/authentication#retrieve-current-authenticated-user

Similarly, you could start with DataStore locally (without pushing anything to the cloud) by working with models until you felt comfortable with shipping:

https://aws-amplify.github.io/docs/js/datastore#save-data

We're actively working on documentation currently, so I've added your original question to our list for support:

Can we also have couple of lines dedicated to how to use amplify with plain old javascript ie without depending on React or anything else?

The docs currently interweave frameworks with the "vanilla" APIs, so we need to address that so it's clear that customers like yourself can benefit from Amplify as-is.

ericclemmons commented 4 years ago

@groundswel I forgot to mention, but the drop-down in our docs has a "JavaScript" option, which will give you the "vanilla" guide:

https://aws-amplify.github.io/docs/js/start?platform=purejs

We discovered a bug with it where the default should have been vanilla JS, but was defaulting to the first option (React). (That's being addressed in a PR)

I hope this helps in the meantime while we continue improving.

I'll go ahead & close this issue since we have some existing documentation, solutions to use "vanilla js", and are tracking improvements internally to remedy this.

Thanks for reaching out!

MartijnHarmenzon commented 4 years ago

@groundswel Did you manage to get this working? Would you be willing to share what you have to do to get this working in a Vanilla JS app? So without frameworks or bundlers.

MartijnHarmenzon commented 4 years ago

@ericclemmons Do you have a simple Amplify Auth example for webpack and Vanilla JS? I am trying to implement the "vanilla guide" https://aws-amplify.github.io/docs/js/start?platform=purejs but it fails.

Using webpack with the following code in app.js, a main.bundle.js file seems to be created in the dist folder.

import Amplify from '@aws-amplify/core';
import Auth from '@aws-amplify/auth';
import aws_exports from './aws-exports';

Amplify.configure(aws_exports);

But using Auth in the index.html results in an error: Uncaught ReferenceError: Auth is not defined

This is the code of the index.html.

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>

<body>

  <script src="main.bundle.js"></script>

  <script>
    const username = 'my.email@address.com';
    const password = 'password1234';

    // You can pass an object which has the username, password and validationData which is sent to a PreAuthentication Lambda trigger
    Auth.signIn({
        username, // Required, the username
        password, // Optional, the password
      }).then(user => console.log(user))
      .catch(err => console.log(err));
  </script>
</body>

</html>

Any ideas?

ericclemmons commented 4 years ago

@MartijnHarmenzon I just ran through https://aws-amplify.github.io/docs/js/start?platform=purejs to validate your use-case and believe I found the solution!

Try moving the code from index.html's <script> tag to src/app.js, after the Amplify.configure(aws_exports), like in the example here:

https://aws-amplify.github.io/docs/js/start#step-4-integrate-into-your-app

Webpack is bundling src/app.js and its dependencies (aws-amplify/auth) into main.bundle.js. The code in index.html isn't processed by webpack, so Auth isn't accessible within those <script> tags, only within the file that has import Auth from "@aws-amplify/auth".

Once all of the custom code is moved out of index.html and under src/app.js, things should work!

MartijnHarmenzon commented 4 years ago

@ericclemmons Thank you for your quick response! I can confirm this approach works. However, this is not the way I would like it to be. My preferred method would be to use Amplify Auth without any build proces. Alternatively, generating the required main.bundle.js file only once and using Auth in any file .html or .js. Is this somehow possible?

MartijnHarmenzon commented 4 years ago

@groundswel Did you manage to get this working? Would you be willing to share what you have to do to get this working in a Vanilla JS app? So without frameworks or bundlers.

I managed to accomplish this by following the instructions here: https://github.com/aws-amplify/amplify-js/tree/master/packages/amazon-cognito-identity-js

By including the following files:

<script src="./aws-sdk-2.610.0.min.js"></script>
<script src="./node_modules/amazon-cognito-identity-js/dist/amazon-cognito-identity.min.js"></script>

To reduce the size of the aws-sdk-*.min.js file I build a custom SDK which only includes the AWS.CognitoIdentity part, using https://sdk.amazonaws.com/builder/js/.

Now my total size is 315kb unzipped (SDK = 233kb, amazon-cognito-identity.min.js = 82kb). I still find this extremely large for some login procedures. Any ways to reduce the required file size even further?

ericclemmons commented 4 years ago

@MartijnHarmenzon You're right on file-size: we have a branch in the works that will help slim that down, but that also relies on bundling tools (e.g. webpack & parcel) to statically analyze your application so it can leave out unused code.

If you want to avoid bundling entirely and expose just the parts you need (e.g. API or Auth), it should only take a few lines!

  1. First, update webpack.config.js to expose your exports from app.js:

    diff --git a/webpack.config.js b/webpack.config.js
    index c4a6dd1..9b61226 100644
    --- a/webpack.config.js
    +++ b/webpack.config.js
    @@ -7,7 +7,10 @@ module.exports = {
       entry: "./src/app.js",
       output: {
         filename: "[name].bundle.js",
    -    path: path.resolve(__dirname, "dist")
    +    path: path.resolve(__dirname, "dist"),
    +    globalObject: "this",
    +    library: "MyApp",
    +    libraryTarget: "umd"
       },
       module: {
         rules: [

    (From https://webpack.js.org/configuration/output/#outputglobalobject)

  2. Next, export whatever you want to make available within the browser window:

    diff --git a/src/app.js b/src/app.js
    index b77b976..61c93fc 100644
    --- a/src/app.js
    +++ b/src/app.js
    @@ -46,3 +47,5 @@ MutationButton.addEventListener("click", evt => {
         MutationResult.innerHTML += `<p>${evt.data.createTodo.name} - ${evt.data.createTodo.description}</p>`;
       });
     });
    +
    +export { API };
  3. Once you rebuild your bundle, you'll be able to access the exports from your bundle via window.MyApp:

    Screen Shot 2020-01-29 at 1 04 02 PM

mauerbac commented 4 years ago

Looks like Eric solved this, so going to close out. Let us know if you have other questions.

ameykshirsagar commented 3 years ago

I was able to do it in this way. It works perfectly



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./node_modules/aws-amplify/dist/aws-amplify.min.js"></script>
    <script>

        aws_amplify.Amplify.configure({
            // content of aws-exports.js
        });

        try {
            const user = aws_amplify.Amplify.Auth.signIn("<username>", "<pass>");
            console.log(user);
        } catch (error) {
            console.log('error signing in', error);
        }

        try {
            const { user } = aws_amplify.Amplify.Auth.signUp({
                username: "<username>",
                password: "<pass>",
                attributes: {
                    email: "<email>" // optional

                }
            });
            console.log(user);
        } catch (error) {
            console.log('error signing up:', error);
        }
    </script>
</head>
<body>

</body>
</html>`
ericclemmons commented 3 years ago

@ameykshirsagar Thanks for sharing! Confirmed that creating index.html with the following (then running npx serve) worked!


<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="./node_modules/aws-amplify/dist/aws-amplify.min.js"></script>
    <script>
      aws_amplify.Amplify.configure({
        // content of aws-exports.js
      });

      aws_amplify.Amplify.Auth.signIn("<username>", "<password>")
        .then(console.info)
        .catch(console.error);
    </script>
  </head>

  <body></body>
</html>
ameykshirsagar commented 3 years ago

I have put up a small blog post in how to do it. https://arcoirislabs.medium.com/aws-amplify-in-vanilla-javascript-6c4d8b3f29b0

masbaehr commented 3 years ago

Hi, i was able to use Amplify with a Vanilla JS project as described. However the minified bundle is 1.4MB . I only need Authentication. Is there any way to shrink it? Thanks!

Kiddinglife commented 3 years ago

@ameykshirsagar @ericclemmons I want to use amplifyjs (specifially I need api cate, auth cate) in my unreal project with the use of ue4 plugin called unrealjs https://github.com/ncsoft/Unreal.js. (I am eager to something like amplify-c++ but there is no such thing). fyi. I am using aws-amplify: "lastest" when I did this test.

I used "require("./amplify/aws-amplify-core-min").default" as ameykshirsagar showed.

"use strict";
const Amplify = require("./amplify/aws-amplify-core-min").default;

It worked but when I did const API = require('./amplify/aws-amplify-api-min');. I got this error:

Error: file:///d:/EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/amplify/amplify.js:5: ReferenceError: window is not defined
Error: ReferenceError: window is not defined
Error:     at file:///d:/EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/amplify/amplify.js:5:41
Error:     at file:///d:/EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/amplify/amplify.js:860:10
Error:     at file:///d:/EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/amplify/amplify.js:17795:4
Error:     at file:///d:/EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/amplify/amplify.js:17796:25
Error:     at file:///../../../../../EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/helloWorld.js:7:17
Error:     at file:///../../../../../EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/helloWorld.js:46:3
< Invalid script for require
Error: file:///../../../../../EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/helloWorld.js:7: TypeError: Cannot read property 'default' of undefined
Error: TypeError: Cannot read property 'default' of undefined
Error:     at file:///../../../../../EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/helloWorld.js:7:45
Error:     at file:///../../../../../EpicEngineProjects/UnrealJS-Examples/Examples/Content/Scripts/helloWorld.js:46:3

I think ameykshirsagar 's solution works well in vanilar/broswer javascript. However, I need a solutio that can work with "plain javascript/node". Any idea ? thank you veru much.

github-actions[bot] commented 2 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 or Discussions for those types of questions.