npm package: @sharechest/connector
Description: (Formerly known as the Launcher)
Latest version: 2.12.1

# Sharechest Connector.

(Formerly known as the Launcher)

The connector is used to walk a prospective investor through the process of providing contact information to the issuer. It communicates with the [core](https://github.com/Sharechest/core) backend to pull details for a company and its promoted activity, and to submit the contact information for the prospective investor ("prospect", in backend model terminology)

### Links

[[npm package](https://www.npmjs.com/package/@sharechest/connector)]
[[unpkg url](https://www.unpkg.com/@sharechest/connector@latest)]
[[connector tickets](https://linear.app/sharechest/view/15017971-34b4-4195-8a5a-abf9a1ba2138)]

### Technologies

- [Svelte](https://svelte.dev)
- [TypeScript](https://www.typescriptlang.org)

# Get started

Install the dependencies...

```bash
cd svelte-app
npm install
```

...then start [Rollup](https://rollupjs.org):

```bash
npm run dev
```

Navigate to [localhost:5000](http://localhost:5000). You should see the app running. Edit a component file in `src`, save it, and reload the page to see your changes.

By default, the server will only respond to requests from localhost. To allow connections from other computers, edit the `sirv` commands in package.json to include the option `--host 0.0.0.0`.

## Building and running in production mode

To create an optimised version of the app:

```bash
npm run build
```

You can run the newly built app with `npm run start`. This uses [sirv](https://github.com/lukeed/sirv), which is included in your package.json's `dependencies` so that the app will work when you deploy to platforms like [Heroku](https://heroku.com).

## Single-page app mode

By default, sirv will only respond to requests that match files in `public`. This is to maximise compatibility with static fileservers, allowing you to deploy your app anywhere.

If you're building a single-page app (SPA) with multiple routes, sirv needs to be able to respond to requests for _any_ path. You can make it so by editing the `"start"` command in package.json:

```js
"start": "sirv public --single"
```

# Directory Structure

- `src/`
  - `api/`
    Modules for communicating with backend and external APIs.
  - `components/`
    Re-usable UI Components.
  - `errors/`
    Enums and modules for error messages, error handling, etc.
  - `globalStores/`
    Stores that are global to the entire connector flow.
    - `company/`
      Holds details for the company that the connector is referencing. This ID comes from the embed code.
  - `node_modules/`
    Strange to see here, but this is a local node*modules that is excluded from the gitignore. It contains our forked version of `svelte-simple-modal`. We needed to make some styling and behaviour changes to the pacakge, so we dropped it straight into the project. VSCode complains, but we _can_ and _do_ import our modal from this local node_modules folder like normal, using an absolute path.
  - `util/`
    Utilities. The index file in here acts as the "public" API for our global utils, re-exporting the things that should be accessible.
  - `views/`
    - Connector views. Basically the equivalent of "pages" for a regular website. This also contains the main router component used for moving between views.
  - `App.js`
    Main Svelte file entry point, which renders the router. When this mounts, it requests the company information from the backend.
  - `index.svelte`
    Renders the button to show/hide the connector on the client website. When it's clicked, it'll open the modal.
  - `main.js`
    Exposes the Svelte app constructor to the window object so our script tags can use it (see Client Integration section below).
  - `polyfill.js`
    Imports all the polyfills we need for IE support.

# Legacy Package

We need at least basic support for IE11, but Svelte doesn't support IE11 out of the box. To get around this, we build a version of the app that has all the required features polyfilled. It only gets built in production mode, so IE will **not** work when running dev mode (`npm run dev`). Testing IE can be done by running `npm run ie` which will build and locally serve a production instance.

---

<details>
<summary>Note: Additional step for "npm run ie"</summary>

When building for prod but intending to run locally, we have to make a small change to our rollup config so the connector still hits a localhost backend endpoint.

- Open rollup.config.js
- Find the `API_URL` definition
- Make the following change:

```diff
-  const API_URL = production
+  const API_URL = !production
    ? "https://sharechest.gigalixirapp.com/api"
    : "http://localhost:4000/api";
```

Remember to discard this change before pushing to a branch!

</details>

---

During a production mode build, rollup will compile both the polyfill file (output -> `public/bundles/polyfill.js`) and the rest of the app (output -> `public/bundles/bundle.js`). After rollup is finished, the next part of the `npm build` command will run Babel on all JS files in the `public/bundles` directory, and output them as `[filename].legacy.js`. Doing so will ensure we generate a `public/bundles/bundle.legacy.js` and `public/bundles/polyfill.legacy.js` file for IE support. Babel does the final transformation of all app code and polyfill packages to ES2015.

When we load these scripts on the client website, we use the `type="module"` and `nomodule` HTML attributes to ensure that the legacy script (`nomodule`) doesn't get downloaded on modern browsers, and the modern script (`type="module"`) never gets executed on legacy browsers.


# Testing

No testing yet, since the scope is so tiny. The plan is to use [Jest](https://jestjs.io) and [@testing-library/svelte](https://testing-library.com/docs/svelte-testing-library) for "unit testing" (fast tests), and [Cypress](https://www.cypress.io) for "e2e testing" (slow tests).

# Deployment

Github Actions CI in the Connector repo will run semantic-release after pull requests to the `main` branch. This will:

1. Build the latest code
2. Create a git tag for the new version number
3. Zip the latest code, and publish to GitHub as a release package, tagged with the new version number
4. Publish the latest code as an npm package under the name `@sharechest/connector`, tagged with the new version number

Once the npm package is published, we rely on [unpkg](https://unpkg.com) (a mirror for everything on npm) as our CDN. It's run through Cloudflare's edge network so has great performance from pretty much anywhere in the world, and it requires no maintenance or work from our end. Plus it's free! Our new code is usually available in the unpkg cache within 5-10 minutes following a deployment.

As shown in the client integration section, we point directly to our CSS and script files on unpkg.

# Notes

## CSS/Styling

Since we're placing the connector on client websites which all have unique CSS rules, there can be styling conflicts which make our elements look or behave wrong. Below are some steps we've taken to avoid this, though new problems occasionally show up, as every website is different.

### Style Resets

Our [global css](https://github.com/Sharechest/connector/blob/main/public/global.css) file gets included on a client's webpage. We use it to target our mount point div (`widget-stake-trunk` as of writing) and apply some overrides to it, in hopes that they'll be accepted by the webpage as more specific to our elements than page's global styles. Notable inclusions are resets of margins & padding, font sizes, and line heights.


## Client Integration

When we need to add the connector to a client's website, we use HTML code containing some scripts and style tags referencing our CDN, and including the client's company ID from our backend. Here's an example of a production snippet for a client:

<!-- prettier-ignore-start -->
```html
<div id="widget-stake-trunk" class="widget-stake-trunk" />
<link rel="stylesheet" href="https://www.unpkg.com/@sharechest/connector@1/public/bundles/bundle.css" />
<link rel="stylesheet" href="https://www.unpkg.com/@sharechest/connector@1/public/global.css" />
<script type="module" src="https://www.unpkg.com/@sharechest/connector@1/public/bundles/bundle.js" ></script>
<script nomodule src="https://www.unpkg.com/@sharechest/connector@1/public/bundles/polyfill.legacy.js" ></script>
<script nomodule src="https://www.unpkg.com/@sharechest/connector@1/public/bundles/bundle.legacy.js" ></script>
<script type="module">
  window.__sharechest_app(
    "widget-stake-trunk",
    "a5079158-7050-4513-91b7-94b90288006a"
  );
</script>
<script nomodule>
  window.__sharechest_app(
    "widget-stake-trunk",
    "a5079158-7050-4513-91b7-94b90288006a"
  );
</script>
```
<!-- prettier-ignore-end -->

The div is the mount point for the connector. We apply style overrides to this element in an attempt to avoid style overrides from the websites we're integrating into.

Following the div, we have some script tags referencing our npm package through unpkg. We reference the bundle JS file with the `type="module"` attribute for modern browsers, and reference the polyfill and legacy bundle JS files with the `nomodule` attribute for IE.

After that are the mounting script blocks, which call the `window.__sharechest_app()` function, passing the mount-point div ID and the company ID from our backend. The mount function here is exposed through the window object from the `main.js` file in the connector root.

# FAQ

## What is `ENV.API_URL`?

Anywhere we write the string `ENV.API_URL`, we're referencing the API URL for the current runtime environment (localhost in development, our production URL (https://api.sharechest.io) in production).

We use `@rollup/plugin-replace` to overwrite these strings at compile-time. Configuration for this can be found in `rollup.config.js`.