Skip to content

Commit

Permalink
Merge branch 'release/2.0' into jimothy/gh-439_theme-vs-storefront
Browse files Browse the repository at this point in the history
  • Loading branch information
jcalcaben authored Nov 16, 2018
2 parents 8f5b91b + 6a8fe53 commit 4bc27d7
Show file tree
Hide file tree
Showing 54 changed files with 17,826 additions and 2,540 deletions.
58 changes: 6 additions & 52 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,62 +60,13 @@ dependencies centrally managed by Lerna.

## Quick Setup

PWA Studio 2.0 requires much less setup than PWA Studio 1.0. The UPWARD architecture means that the Magento instance does not need to be configured to use your project as a theme. Instead, you connect to your Magento instance by simply specifying its URL in your environment.

### Obtain Magento 2.3

1. Make sure the Magento instance you're using is set to development mode, and has the latest 2.3.

* You need development mode for GraphQL introspection queries to work.
* The latest codebase will have the most up-to-date GraphQL schema.

2. Ensure that the Venia sample data is installed on the Magento instance. (**TODO: painless instructions for the Composer commands to do that**)

One simple way to obtain Magento 2.3 is using the [Core Contributor Vagrant box](https://github.com/paliarush/magento2-vagrant-for-developers/).

#### Using the Vagrant Box

1. Clone the https://github.com/paliarush/magento2-vagrant-for-developers/ repository and follow the [setup instructions](https://github.com/paliarush/magento2-vagrant-for-developers/#installation-steps).

2. Make sure that all [sample data auto-installation parameters in the config.yaml](https://github.com/paliarush/magento2-vagrant-for-developers/blob/2.0/etc/config.yaml.dist#L49-L51) file are disabled.

3. When installation is complete, then install the Venia sample data. Copy [this shell script](https://gist.github.com/mhhansen/19775bcf93614f5f9db34b90273fa2b8) and save it in your Magento root directory as `installVeniaSampleData.sh`.

4. Run `vagrant ssh` to login to the Magento VM.

5. Run `bash installVeniaSampleData.sh`. The Venia sample data should install, and the Vagrant host is ready to use.

6. Update your `.env` file in PWA Studio to set `MAGENTO_BACKEND_URL` to the URL of the Vagrant box.

### Install Dependencies

_**Note**: You must have a version of `node.js` >= `8.0.0`, and a version of `npm` >= `5.0.0`. The latest LTS versions of both are recommended._

Follow these steps to install the dependencies for all the packages in the project:

1. Clone the repository.
2. Navigate to the root of the repository from the command line
3. Run `npm install`
4. Copy `packages/venia-concept/.env.dist` to `packages/venia-concept/.env`
5. Uncomment the line for `MAGENTO_BACKEND_URL` in `packages/venia-concept/.env`, and set `MAGENTO_BACKEND_URL` to the fully-qualified URL of a Magento store running `2.3`.
6. On your first install, run `npm run build` from package root.
7. To run the Venia storefront development experience, run `npm run watch:venia` from package root.
See the [Venia storefront setup][] topic for instructions on installing this project's dependencies and running the Venia storefront on top of an existing Magento backend.

## Troubleshooting

### When I run the developer mode, I get validation errors

Make sure you have created a `.env` file in `packages/venia-concept` which specifies variables for your local development environment. You can copy from the template `packages/venia-concept/.env.dist`.

### Venia queries to GraphQL produce validation errors

Venia and its GraphQL queries may be out of sync with the schema of your connected Magento instance. Make sure the Magento instance is up to date with the 2.3 development branch, and your copy of this repository (or your dependency on it) is up to date.

### My browser complains that the connection is not secure

Generating certificates is handled by [devcert](https://github.com/davewasmer/devcert). If you're on a Linux machine make sure that `libnss3-tools` (or whatever the equivalent is) is installed on your system. Further information provided in [this section of the devcert readme](https://github.com/davewasmer/devcert#skipcertutil).
See our [Troubleshooting][] guide if you run into any problems.

**To test whether your queries are up to date, run `npm run validate-queries` at project root.**
If you have an issue that cannot be resolved, please [create an issue][].

## Things not to do

Expand All @@ -131,6 +82,9 @@ Generating certificates is handled by [devcert](https://github.com/davewasmer/de
[Greenkeeper badge]: https://badges.greenkeeper.io/magento-research/pwa-studio.svg
[Contribution guide]: .github/CONTRIBUTING.md
[Git hook]: <https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks>
[Venia storefront setup]: https://magento-research.github.io/pwa-studio/venia-pwa-concept/setup/
[Troubleshooting]: https://magento-research.github.io/pwa-studio/pwa-buildpack/troubleshooting/
[create an issue]: https://github.com/magento-research/pwa-studio/issues/new

[mage2pratik]: https://github.com/mage2pratik
[mage2pratik-image]: https://avatars0.githubusercontent.com/u/33807558?s=120&v=4
Expand Down
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "2.0.0-rc.5",
"version": "2.0.0-rc.10",
"packages": [
"packages/peregrine",
"packages/pwa-buildpack",
Expand Down
191 changes: 2 additions & 189 deletions packages/peregrine/docs/RestApi.md
Original file line number Diff line number Diff line change
@@ -1,192 +1,5 @@
# REST API Clients

Peregrine includes functions to efficiently manage requests to a REST API. The default implementation is for the Magento 2 REST API. Use a REST client in a Peregrine app to work with non-GraphQL Web APIs.
Documentation has been moved to the [REST API client][] topic in the PWA devdocs site.

## Magento 2 REST API Client

<a name="request"></a>

## request(resourceUrl, opts) ⇒ <code>Promise</code>

Place a request to the Magento 2 REST API and return a Promise for the response.

The API of `request` is identical to the Web standard [fetch][1], with the
following differences and additions:

### REST Response Handling

**The `request()` method returns a promise for a fully parsed REST resource**, not for an HTTP
response as in the standard `fetch` API. Conceptually, an HTTP response is the transport layer for a REST resource, and its properties must be interpreted by the rules of the API contract to produce an actual REST resource representation. So while `request` emulates the `fetch` API, it returns Promises for Magento REST resources, not for the HTTP responses that may transmit them. Instead of returning a `Response` object, which must then be streamed as JSON via `response.json()`, `request` returns an optimistically parsed resource.

The `Response` object is still available; you may restore `fetch` behavior by setting the special option `parseJSON` to `false`. When `parseJSON` is set to `false`, the Promise will resolve to a `Response` object which you can manipulate directly.

### REST Error Handling

**Promises returned by the `request()` method will reject if the server responds with an HTTP error code (4xx-5xx)**, whereas the standard `fetch` will ignore HTTP errors and resolve the promise, only failing on network connectivity errors.

Like HTTP response bodies, HTTP response statuses are significant in a REST API because they represent server-side results. A Promise representing a failed operation should reject, and the Magento REST API uses HTTP error codes to denote failed operations. Instead of resolving Promises for HTTP error statuses, `request` will build an error containing as much metadata as is possible for debugging, and reject the Promise.

### Multicasting In-Flight Requests

**Successive calls to the `request()` method for the exact same resource may result in a single request and response being shared by all callers**, instead of placing simultaneous HTTP requests as in the stock `fetch`.

A problem exists in any distributed architecture, where applications are built from components which include view, behavior, and data fetching strategy. Multiple components may request the same resource at the same time, resulting in redundant requests. GraphQL clients resolve this by merging GraphQL queries together, dispatching a request as a single call, and then distributing the pieces of the GraphQL response to the original callers. A direct `fetch` or `XMLHttpRequest` has no such functionality.

The `request()` method makes up for that, to some extent, by using a pattern-matching rule on inflight requests. If a request is in progress (that is, the network hasn't loaded the resource yet), and a new request is made that appears to be for the same resource, and no unsafe operations (such as POSTS, usually) have happened to that resource in the interim, `request()` may respond to the second call with a clone of the first reaponse.

This behavior, called `multicast`, is controllable with another special option. Multicast runs automatically on any request that is not a POST with a body (since POSTS with bodies are neither safe nor idempotent, they must all be executed for the server to be in a known state). You can force any request to opt out of multicast by passing `multicast: false` in your Options object. In the same vein, you can force an unsafe request to opt in to multicast by arguing `multicast: true` as an option.

### Rolling Requests

**When `request` is called with an explicit `cache` value of `reload` or `no-store`, it overrides and replaces any multicasting matching request. It will still participate in multicast, but it will override all other previous calls. This is a common use case for retrieving the freshest version of a resource you just changed (such as the cart).

### Usage

Import the `request()` function into another module using ES6 imports:

```js
import { RestApi } from '@magento/peregrine';
const {
Magento2: { request }
} = RestApi;
```

Place and receive API calls using `async/await` syntax.

```js
async function displayGuestCartItems(cartId) {
const cartResponse = await request({
method: 'GET',
path: 'guest-carts/${cartId}'
});
const cart = await cartResponse.json();
console.log(cart.items);
}
```

Alternatively, use Promise objects directly.

```js
function displayGuestCartItems(cartId) {
return request({
method: 'GET',
path: 'guest-carts/${cartId}'
})
.then(({ items }) => console.log(items);)
}
```

## Multicasting

The Magento 2 REST client **multicasts qualifying requests by default**. A
"qualifying request" is any request known to be idempotent in the Magento 2 REST
API. Multiple equivalent calls (such as a GET with the same PATH, or a PUT with
the same body) will not be placed at the same time; instead, the first matching
request will be multicast. All requests with the same method, path, and body
text are considered multicastable by default, except for `POST` requests with a
non-empty body. `POST` requests may be creating and/or modifying server state,
so it is unsafe to reuse results.

### Overriding Multicast

The `multicast` option forces multicasting to be either true or false, bypassing
the rules described above.

```js
// A normally multicast request forced not to multicast
request({ method: 'GET', path: 'carts/mine', multicast: false });
// A normally non-multicast request forced to multicast
request({
method: 'POST',
path: 'carts/mine/items',
body: cartItem,
multicast: true
});
```

### Rolling Requests

A rolling request, like a "rolling build" in continuous integration, is a
multicast request which **overrides and replaces the matching previous request
that was multicasting.** It aborts any outstanding matching requests, saving
on network traffic while maintaining a fresh resource.

The `rolling` option makes a request roll over any matching prior requests. On
non-multicast requests, it has no effect.

## The `Magento2ApiRequest` Class

The `request()` method is a convenience wrapper on top of the
`Magento2ApiRequest` class. For advanced cases, use `Magento2ApiRequest`
instances directly.

```js
import { RestApi } from '@magento/peregrine';
const { M2ApiRequest } = RestApi;

function placeCancelable(emitter) {
const req = new M2ApiRequest({
method: 'GET',
path: 'some/slow/large/resource'
});
req.run();
emitter.on('someevent', () => {
req.abortRequest();
});
return req.getResponse(); // AbortError
}
```

<a name="M2ApiRequest"></a>

- [new M2ApiRequest(opts)](#new_M2ApiRequest_new)
- [.run()](#M2ApiRequest+run)
- [.getResponse()](#M2ApiRequest+getResponse) ⇒ <code>Promise</code>
- [.abortRequest()](#M2ApiRequest+abortRequest)
- [.isRolling()](#M2ApiRequest+isRolling) ⇒ <code>boolean</code>

<a name="new_M2ApiRequest_new"></a>

### new M2ApiRequest(opts)

| Param | Type |
| ----- | -------------------------------------------------------- |
| opts | [<code>M2ApiRequestOptions</code>](#M2ApiRequestOptions) |

<a name="M2ApiRequest+run"></a>

### m2ApiRequest.run()

Execute the request. Must be run before [getResponse](#M2ApiRequest+getResponse)
or [M2ApiRequest#cancel](M2ApiRequest#cancel) can be called.

<a name="M2ApiRequest+getResponse"></a>

### m2ApiRequest.getResponse() ⇒ <code>Promise</code>

Get the promise for the network operation. Can only be called after
`.run()` is called.
Exists so that requests can reuse the promises from other requests.

**Returns**: <code>Promise</code> - Promise for the result of the request.
<a name="M2ApiRequest+abortRequest"></a>

### m2ApiRequest.abortRequest()

Abort the network operation. Multicasted requests catch the AbortError
and attempt to reuse a more recent matching request from cache. Other
requests will pass the AbortError rejection through to the consumer.

**Kind**: instance method of [<code>M2ApiRequest</code>](#M2ApiRequest)
<a name="M2ApiRequest+isRolling"></a>

### m2ApiRequest.isRolling() ⇒ <code>boolean</code>

Check if this request intends to override prior requests to the same
resource. Rolling requests will take the place of prior outstanding
requests, to ensure the freshest resource at the cost of additional
network calls.

**Returns**: <code>boolean</code> - True if the request is rolling.

1: <https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch>
[REST API client]: https://magento-research.github.io/pwa-studio/peregrine/reference/rest-api-client/
24 changes: 2 additions & 22 deletions packages/peregrine/docs/Router.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,6 @@
# Peregrine Router

The Peregrine Router is a client-side router that is designed to understand the
different storefront routes within Magento 2. If using Peregrine to bootstrap
your PWA, it is configured automatically. If not, the Router can be manually
consumed.
Documentation content has been moved to the [Router][] topic in the PWA devdocs site.

## Manual Usage
[Router]: https://magento-research.github.io/pwa-studio/peregrine/reference/router/

```jsx
import ReactDOM from 'react-dom';
import { Router } from '@magento/peregrine';

ReactDOM.render(
<Router apiBase="https://mystore.com" />,
document.querySelector('main')
);
```

## Props

| Prop Name | Required? | Description |
| ------------- | :-------: | -----------------------------------------------------------------------------------------------------: |
| `apiBase` || Root URL of the Magento store, including protocol and hostname |
| `using` | | The Router implementation to use from React-Router. Can be `BrowserRouter`/`HashRouter`/`MemoryRouter` |
| `routerProps` | | Any additional props to be passed to React-Router |
Loading

0 comments on commit 4bc27d7

Please sign in to comment.