npm package: @shopify/loom-plugin-build-library-extended
Description: loom consumer plugin for additional file types when building libraries
Author: Shopify Inc.
Latest version: 2.2.0

# `@shopify/loom-plugin-build-library-extended`

This package is a compliment to [`@shopify/loom-plugin-build-library`](https://github.com/Shopify/loom/tree/main/packages/loom-plugin-build-library). It enhances the build provided by `@shopify/loom-plugin-build-library`, teaching Rollup and Jest about additional file types. It provides support for parsing styles (`.scss` files), images (`.svg`, `.jpg`, `.png` files) and graphql (`.graphql` files). In also provdes type generation for graphql files.

It exposes two plugins - `buildLibraryExtended` and `buildLibraryExtendedWorkspace` that should be added to your loom plugins after the `buildLibrary` and `buildLibraryWorkspace` plugins provided by `@shopify/loom-plugin-build-library`.

## Installation

```sh
$ yarn add @shopify/loom-plugin-build-library-extended --dev
```

## Usage

Add `buildLibraryExtended` and `buildLibraryExtendedWorkspace` to your loom plugins.

```js
import {createPackage, Runtime} from '@shopify/loom';
import {
  buildLibrary,
  buildLibraryWorkspace,
} from '@shopify/loom-plugin-build-library';
import {
  buildLibraryExtended,
  buildLibraryExtendedWorkspace,
} from '@shopify/loom-plugin-build-library-extended';

export default createPackage((pkg) => {
  pkg.entry({root: './src/index.js'});
  pkg.use(
    buildLibrary({
      targets: 'defaults, node 12.22',
      commonjs: true,
      esmodules: true,
      esnext: true,
    }),
    buildLibraryWorkspace(),
    buildLibraryExtended({
      // Optional. Defaults to false. Defines if graphql files should be processed.
      graphql: false,
    }),
    buildLibraryExtendedWorkspace({
      // Optional. Defaults to false. Defines if d.ts files should be generated for graphql files.
      graphql: false,
      // Optional. Defaults to `{}`. Defines any overrides for typescript generation, such as exportFormat and customScalars.
      // See https://github.com/Shopify/quilt/blob/main/packages/graphql-typescript-definitions/README.md#node
      generateGraphqlOptions: {},
    }),
  );
});
```

### Styles

`.scss` files shall be processed using [`dart-sass`](https://sass-lang.com/dart-sass), [`PostCSS`](https://postcss.org/) and [`postcss-modules`](https://github.com/madyankin/postcss-modules). [`@shopify/postcss-plugin`](https://github.com/Shopify/web-configs/tree/main/packages/postcss-plugin) is used to apply autoprefixing of vendor prefixes and other style transforms.

Create scss files and import them into your JS/TS files. Each style file will expose a default export that is an object containing classnames defined in your style file.

```scss
// component.scss
.MyStyle {
  color: red;
}
.MySecondStyle {
  color: blue;
}
```

```tsx
// component.tsx
import styles from './component.scss';

export function Component() {
  return (
    <>
      <div className={styles.MyStyle}>I am red</div>
      <div className={styles.MySecondStyle}>I am blue</div>
    </>
  );
}
```

Currently plain `.css` files are not supported.

In `esmodules` builds a `styles.css` file shall be created at in `build/esm/styles.css` containing all your scss files concatenated in the order of import. Consuming applications must import this style file. Currently creating a css file per input entrypoint is not supported.

In `esnext` builds a `.css` file will be created per `.scss` file in your source and imports to scss files are placed with imports to the `.css` file. This allows consumers that understand esnext builds to only include the styles for the components it uses, instead of having to load the styles for all components.

### Images

`.svg`, `.png` and `.jpg` expose a default export that is a base64 representation of the image. This value can then be used as the `src` attribute of `img` tags. This is good for small images but is an inefficient way of handling larger image. This functionality is provided by [`@rollup/plugin-image`](https://www.npmjs.com/package/@rollup/plugin-image).

```tsx
// component.tsx
import myImage from './images/my-image.svg';

export function Component() {
  return <img src={myImage} alt="" />;
}
```

An exception to this is svg files inside an `icons` folder, which shall expose the svg represented as a React component. This allows the image to be rendered as a React component, or passed into `@shopify/polaris`'s `Icon` component. This functionality is provided by [`@svgr/rollup`](https://www.npmjs.com/package/@svgr/rollup).

```tsx
// component.tsx
import {Icon} from '@shopify/polaris';
import MyIcon from './icons/my-icon.svg';

export function Component() {
  return (
    <>
      <MyIcon />
      <Icon source={MyIcon} />
    </>
  );
}
```

### GraphQL

`.graphql` files expose a default export that is the query provided by the file. This functionality is provided by [`@rollup/plugin-graphql`](https://www.npmjs.com/package/@rollup/plugin-graphql).

```graphql
# bookList.graphql
query BookList {
  books {
    id
    title
    genre
  }
}
```

```tsx
// component.tsx
import {useQuery} from '@shopify/react-graphql';
import bookList from './myQuery.graphql';

export function Component() {
  const {data, error, loading} = useQuery(bookList);
  return JSON.stringify({data, error, loading});
}
```

When you call `buildLibraryExtendedWorkspace({graphql: true})` `.d.ts` files shall be generated for all graphql files as part of your pre-build and type-check steps using [`graphql-typescript-definitions`](https://www.npmjs.com/package/graphql-typescript-definitions). This exposes type exports of GraphQL data shapes. For instance in the above example `bookList.graphql`shall expose a `BookListQuery` interface. This requires the presense of a `.graphqlconfig` file that references your schema. See `graphql-typescript-definitions`'s readme for more information on how to configure this.

### Generate graphql types that enable type inferrence with Apollo 3's hooks

By default `graphql-typescript-definitions` generates types that enable type inferrence in the hooks provided by `@shopify/react-graphql` and other quilt-based packages. If you want to use Apollo 3's hooks instead, you must adjust the `exportFormat` option.

If you need types that work with both `@graphql-typed-document-node/core` (used by Apollo 3) and `graphql-typed` (used by `@shopify/react-graphql` and other quilt-based packages) use `ExportFormat.DocumentWithTypedDocumentNode`. You only need Apollo 3 support use `ExportFormat.TypedDocumentNode`. You must be using at least `graphql-typescript-definitions` v3.3.0 to use these value.

```js
import {createPackage, Runtime} from '@shopify/loom';
import {
  buildLibrary,
  buildLibraryWorkspace,
} from '@shopify/loom-plugin-build-library';
import {
  buildLibraryExtended,
  buildLibraryExtendedWorkspace,
} from '@shopify/loom-plugin-build-library-extended';
import {ExportFormat} from 'graphql-typescript-definitions';

export default createPackage((pkg) => {
  pkg.entry({root: './src/index.js'});
  pkg.use(
    buildLibrary({
      targets: 'defaults, node 12.22',
      commonjs: true,
      esmodules: true,
      esnext: true,
    }),
    buildLibraryWorkspace(),
    buildLibraryExtended({graphql: true}),
    buildLibraryExtendedWorkspace({
      graphql: true,
      generateGraphqlOptions: {
        exportFormat: ExportFormat.DocumentWithTypedDocumentNode,
      },
    }),
  );
});
```

### Overriding PostCSS config

We provide an initial PostCSS config that supports autoprefixing, using `@shopify/postcss-plugin`. If you need to adjust this config, you can call the `postcss()` plugin after `buildLibraryExtended` to override the defaults.

```js
import {createPackage} from '@shopify/loom';
import {
  buildLibrary,
  buildLibraryWorkspace,
} from '@shopify/loom-plugin-build-library';
import {
  buildLibraryExtended,
  buildLibraryExtendedWorkspace,
  postcss,
} from '@shopify/loom-plugin-build-library-extended';
import {myPostcssPlugin} from 'my-postcss-plugin';

export default createPackage((pkg) => {
  pkg.entry({root: './src/index.js'});
  pkg.use(
    buildLibrary({targets: 'node 12.22.0', commonjs: true}),
    buildLibraryWorkspace(),
    buildLibraryExtended(),
    buildLibraryExtendedWorkspace(),
    // Override initial postcss options.
    // Return a new object, instead of mutating the argument object.
    postcss({
      config(postcssConfig) {
        return {
          ...postcssConfig,
          plugins: [...(postcssConfig.plugins || []), myPostcssPlugin()],
        };
      },
    }),
  );
});
```