# sewing_kit [![Build status](https://badge.buildkite.com/e7cdc87e61b9fe80e91e8686b6bfba53ca26a36366eb811a50.svg)](https://buildkite.com/shopify/sewing-kit-gem-ci)
Zero configuration, high performance front end development at organization scale.
`sewing_kit` facilitates legacy Rails integration using ERB tags. For a more complete modern stack with performance-as-a-feature, consider [quilt_rails](https://github.com/Shopify/quilt/tree/master/gems/quilt_rails). For details of the `sewing-kit` node package's configuration and usage, see the [sewing-kit README](/README.md).
## Quick Start
Create a Rails project using `dev init` then:
### Install Sewing Kits
```sh
# Add Ruby/Node dependencies
bundle add sewing_kit
yarn add @shopify/sewing-kit
# Optional - add Polaris
yarn add @shopify/polaris react react-dom
yarn
dev up
```
### Add JavaScript
sewing_kit looks for JavaScript in `app/ui/index.js`. The code in `index.js` (and any imported JS/CSS) will be built into a `main` bundle.
### Link to JS/CSS with `erb` Helpers
The `main` bundle is imported into `erb` files using Rails helpers:
```erb
<%= sewing_kit_link_tag *sewing_kit_assets('main', extension: 'css') %>
<%= sewing_kit_script_tag *sewing_kit_assets('main') %>
```
**Note:** CSS `` tags appear only in production; in development, CSS is embedded within the `main.js` bundle.
## Minimal Project Layout
```
├── Gemfile (must contain "gem 'sewing_kit")
├── package.json (must specify '@shopify/sewing-kit' as a 'devDependency')
│
└── app
└── ui
│ └─- index.js
└── views
└─- layouts
└─- application.html.erb (must link to JS / CSS using sewing_kit_script_tag / sewing_kit_link_tag
```
## Rails, Polaris, and React Layout
A typical Polaris app will use React to render views and components. The following layout shows best practice locations for:
- Global SCSS settings
- App sections (roughly analogous to Rails routes)
- Components
- Co-located CSS modules
- Co-located unit tests
```
└── app
└── ui
├─- index.js (renders React into the DOM)
├── styles (optional)
│ └── settings.scss (global vars and @polaris overrides)
│
└── tests (optional)
│ └── each-test.ts
│ └── setup.ts
└── components (optional)
├── App
│ ├── index.js
│ ├── App.js
│ └── tests
│ └── App.test.js
│
├-─ MyComponent
│ ├-─ index.js
│ ├-─ MyComponent.js
│ ├── MyComponent.scss (optional; component-scoped CSS styles, mixins, etc)
│ └── tests
│ └── MyComponent.test.js
│
└── sections (optional; container views that compose presentation components into UI blocks)
└── Home
├-─ index.js
└── Home.js
```
## React Boilerplate
- Create a React app in `app/ui/App.js` ([example](https://github.com/Shopify/sewing-kit-gem-example/blob/master/app/ui/App.jsx))
- In an `erb` view, add a placeholder for React content ([example](https://github.com/Shopify/sewing-kit-gem-example/blob/master/app/views/home/index.html.erb#L4))
- In `index.js`, render a React component into the placeholder element ([example](https://github.com/Shopify/sewing-kit-gem-example/blob/master/app/ui/index.js))
- Use `sewing_kit_script_tag`/`sewing_kit_link_tag` helpers to link erb/js ([example](https://github.com/Shopify/sewing-kit-gem-example/blob/master/app/views/layouts/application.html.erb#L8))
## Testing the front end
For fast tests with consistent results, test front-end components using Jest instead of Rails integration tests.
Use [`sewing-kit test`](https://github.com/Shopify/sewing-kit/blob/master/docs/commands/test.md#L3) to run all `.test.tsx` files in the `app/ui` directory. [Jest](https://jestjs.io) is used as a test runner, with customization available via [its sewing-kit plugin](https://github.com/Shopify/sewing-kit/blob/master/docs/plugins/jest.md).
### Testing React
For testing React applications we provide and support [`@shopify/react-testing`](https://github.com/Shopify/quilt/tree/master/packages/react-testing).
#### Example
Given a component `MyComponent.tsx`
```tsx
// app/components/MyComponent/MyComponent.tsx
export function MyComponent({name}: {name: string}) {
return
Hello, {name}!
;
}
```
A test would be written using Jest and `@shopify/react-testing`'s `mount` feature.
```tsx
// app/components/MyComponent/tests/MyComponent.test.tsx
import {MyComponent} from '../MyComponent';
describe('MyComponent', () => {
it('greets the given named person', () => {
const wrapper = mount();
// toContainReactText is a custom matcher provided by @shopify/react-testing/matchers
expect(wrapper).toContainReactText('Hello, Kokusho');
});
});
```
### Test setup files
By default, the jest plugin will look for test setup files under `/app/ui/tests`.
`setup` can be used to add any custom polyfills needed for the testing environment.
```tsx
// app/ui/tests/setup.ts
import 'isomorphic-fetch';
import 'raf/polyfill';
import {URL, URLSearchParams} from 'url';
(global as any).URL = URL;
(global as any).URLSearchParams = URLSearchParams;
```
`each-test` can be used for any logic that needs to run for each individual test suite. Any setup logic that needs to happen with `jest` globals in scope, such as importing custom matchers, should also be done here.
```tsx
// app/ui/tests/each-test.ts
// we cannot import these in `setup` because `expect` will not be defined
import '@shopify/react-testing/matchers';
beforeAll(() => {
console.log('I will run before every test suite');
});
beforeEach(() => {
console.log('I will run before every test case');
});
afterEach(() => {
console.log('I will run after every test case');
});
afterAll(() => {
console.log('I will run after every test suite');
});
```
For more complete documentation of the jest plugin see [it's documentation](/docs/plugins/jest.md).
### Rails tests
Building JavaScript assets for Rails tests adds friction to test driven development, but some projects rely on tests that intermingle erb / JavaScript behaviour. To accommodate different test styles, sewing_kit offers two test modes.
#### `:return_no_assets` - sewing_kit helpers return empty arrays (default)
As noted above, the Web Foundation team highly recommends `sewing-kit test` for front end testing. Projects following this recommendation can use sewing_kit's default behaviour for controller, integration tests, and e2e tests. Note that no sewing_kit content will appear in pages with this mode enabled.
The default behaviour is equivalent to this configuration:
```rb
# config/initializers/sewing_kit.rb
SewingKit.configure do |config|
config.test_manifest_mode = :return_no_asets
end
```
#### Use precompiled assets
If end-to-end tests are unavoidable:
- Add extra steps to your test commands and CI pipelines that run `sewing-kit build --mode test` before test startup
- Configure sewing_kit's `test_manifest_mode` to use precompiled assets:
```rb
# config/initializers/sewing_kit.rb
SewingKit.configure do |config|
config.test_manifest_mode = :use_precompiled_assets
end
```
If your tests require production assets, precompile using `sewing-kit build --mode production` instead.
## FAQ
### Which version of sewing-kit can I use?
Assume that the sewing*kit gem's latest minor version requires \_at least* the same minor version of the sewing-kit package.
If sewing-kit makes a breaking change, this gem's minor version will be bumped to match the required sewing-kit version.
### How can I fix production builds that are failing due to missing devDependencies?
By moving everything into `package.json#dependencies`. This is necessary because Rails 5.2 prunes `devDependencies` during asset compilation.
### How can I test a production verison of my changes?
Ideally, by deploying to a `staging` environment. If that is not possible, a production-like local development experience is available via:
```sh
NODE_ENV=production SK_SIMULATE_PRODUCTION=1 bundle exec rake assets:precompile
NODE_ENV=production SK_SIMULATE_PRODUCTION=1 dev run
```
Note:
- Code changes will not be automatically recompiled in this state
- `SK_SIMULATE_PRODUCTION` does not make Rails itself run in production mode
- The most accurate way to gauge performance of the production version of an application is via a `staging` environment
After verifying production behaviour, run `bundle exec rake assets:clobber` to get back to development mode.
### My project is using `sprockets-commoner`, can I use sewing_kit too?
No. sprockets-commoner uses an outdated Babel version, and is no longer compatible with sewing-kit.
## sewing-kit's logs are too noisy. How can I see less of them?
sewing-kit defaults to using the same `log_level` as Rails' built in logger. It can be customized this using a configuration block:
```ruby
SewingKit.configure do |config|
config.log_level = :warn # may be `:inherit`, `:debug`, `:info`, `:warn`, or `:error`
end
```
### How can I set breakpoints for server rendered apps?
Start your Rails server with `SK_DEBUG` set as an environment variable, and configure your Node debugger to listen on port `5858`.
```bash
SK_DEBUG=1 bundle exec rails start
```