npm package: @moxy/next-common-files
Description: Next.js plugins that configure webpack with loaders for common files.
Author: João Silva
Latest version: 2.0.1

# next-common-files

[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][build-status-image]][build-status-url] [![Coverage Status][codecov-image]][codecov-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]

[npm-url]:https://npmjs.org/package/@moxy/next-common-files
[downloads-image]:https://img.shields.io/npm/dm/@moxy/next-common-files.svg
[npm-image]:https://img.shields.io/npm/v/@moxy/next-common-files.svg
[build-status-url]:https://github.com/moxystudio/next-common-files/actions
[build-status-image]:https://img.shields.io/github/workflow/status/moxystudio/next-common-files/Node%20CI/master
[codecov-url]:https://codecov.io/gh/moxystudio/next-common-files
[codecov-image]:https://img.shields.io/codecov/c/github/moxystudio/next-common-files/master.svg
[david-dm-url]:https://david-dm.org/moxystudio/next-common-files
[david-dm-image]:https://img.shields.io/david/moxystudio/next-common-files.svg
[david-dm-dev-url]:https://david-dm.org/moxystudio/next-common-files?type=dev
[david-dm-dev-image]:https://img.shields.io/david/dev/moxystudio/next-common-files.svg

Next.js plugins that configure webpack with loaders for common files.

Projects developed with Next.js have to manually insert rules in the configuration file for handling file types that are potentially very common across multiple projects.

These plugins quicken the initial setup of a project by removing that effort from the process, demanding less time from the developer.

## Installation

```sh
$ npm install --save @moxy/next-common-files
```

## Usage

For single usage:

```js
// next.config.js
const { withRasterImages } = require('@moxy/next-common-files');

module.exports = withRasterImages({
    /* options */
});
```

For using multiple plugins, you can use [`next-compose-plugins`](https://github.com/cyrilwanner/next-compose-plugins). The examples in this README will follow the `next-compose-plugins` structure.

```js
// next.config.js
const { withRasterImages, withPlayback, withFonts, withSVG, with3D } = require('@moxy/next-common-files');
const withPlugins = require('next-compose-plugins');

module.exports = withPlugins([
        withRasterImages(),
        withPlayback(),
        withFonts(),
        withSVG(),
        with3D(),
        withJSON5(),
    ]);
```

## Loaders

All plugins default to using [`url-loader`](https://github.com/webpack-contrib/url-loader) with the `limit` option set to `0`, which forces a fallback to [`file-loader`](https://github.com/webpack-contrib/file-loader). This means that, in practice, developers must opt in for `url-loader`'s base64 translation. Developers can choose to set a higher limit in conjunction with other rule options to accommodate the structure of their own project.

With the SVG plugin, [`svgo-loader`](https://github.com/rpominov/svgo-loader) is added to optimize the SVG files. The SVG plugin can also give an inline output, toggled using an `inline` option. When *true*, this plugin also uses [`svg-css-modules-loader`](https://github.com/kevin940726/svg-css-modules-loader), which uniquifies CSS classes in the SVG file.

## Options

All plugins can be passed an options object that will spread to the `webpack` rule. With one exception, explored further below in the SVG section, you can also expect the object to spread to the `url-loader` configuration. You can refer to the [`webpack rule documentation`](https://webpack.js.org/configuration/module/#rule) and the [`url-loader documentation`](https://github.com/webpack-contrib/url-loader#readme) for more details on available options.

Below you can find some common, general examples on how to use the plugins. Please refer to the section specific to each plugin further below for detailed information about each and specifics on how to use them.

Excluding a directory:

```js
// Exclude /images/ directory
withRasterImages({
    exclude: /images\/.*$/,
}),
```

Excluding a file by suffix:

```js
// Exclude files with '.data-url' suffix
withRasterImages({
    exclude: /\.data-url\./,
}),
```

Setting the `url-loader` limit:

```js
// Set higher limit
withRasterImages({
    options: {
        limit: 300000,
    },
}),
```

Using limit and exclude/include to delineate between data URL items and standard items:

```js
// Exclude files with '.data-url' suffix
withRasterImages({
     exclude: /\.data-url\./,
}),

// Set a higher limit for files with '.data-url' suffix
withRasterImages({
    include: /\.data-url\./,
    options: {
        limit: 300000,
    },
}),
```

Using all plugins with options accommodated to an example project structure:

```js
withRasterImages({
    exclude: /favicons\/.*$/,
}),
withPlayback(),
withFonts({
    options: {
        limit: 50000,
    },
}),
withSVG({
    exclude: /\.inline\./,
}),
withSVG({
    include: /\.inline\./,
    inline: true,
}),
```

If you want to set a top limit that would cover all file sizes, you can set the limit as `Infinity`. **Keep in mind**, using data-url or inline content will **increase the size of your bundle**, and defaulting to `Infinity` can lead to an unchecked increase in bundle size.


```js
withRasterImages({
    options: {
        limit: Infinity, // All files will pass
    },
}),
```

## API

### raster-images

This plugin is meant to handle **raster images**, and tests the file types `.png`, `.jpg`, `jpeg`, `.gif`, `.webp` and`.ico`.

> ⚠️ This plugin disables image static imports in your `next.config.js` file. Check https://nextjs.org/docs/basic-features/image-optimization#disable-static-imports for more information.

### playback

This plugin is meant to handle **video** and **audio** files, and tests the file types `.mp3`, `.flac`, `.wav`, `.aac`, `.ogg`, `.oga`, `.mp4`,  `.m4a`, `.webm` and `.ogv`.

### fonts

This plugin is meant to handle **font** files, and tests the file types `.eot`, `.ttf`, `.woff`, `.woff2` and `.oft`.

### svg

This plugin is meant to handle **SVG** files,  and tests the file type `.svg`.

This plugin adds the [`svgo-loader`](https://github.com/rpominov/svgo-loader) to optimize the SVG files it loads. 

Though it defaults to working like the previous plugins, this plugin can also output inline content. You can toggle the output by sending an `inline` option, which is set to *false* by default. Use this if you want to be returned a `string` with the content of the SVG file. When *false* the plugin will behave like the others, using `url-loader` together with `svgo-loader`. When *true*, the plugin will use a different set of loaders, including [`svg-css-modules-loader`](https://github.com/kevin940726/svg-css-modules-loader), which uniquifies the CSS classes in the file.

The available options also change in accordance with the `inline` value. With the `inline` option set to *false*, it will behave like the other plugins. With the `inline` option set to *true*, the options object will safely spread **only to the rule**, and passing the `use` option will **override the default loaders entirely**.

```js
// If false or not sent, options can be sent like other plugins
withSVG({
    options: {
        limit: 20000,  // Will be safely passed to url-loader
    },
}),

// If sent true, 'use' value will override default loaders entirely
withSVG({
    include: /\.inline\./,  // Will be safely passed to rule
    inline: true,
    use: [{
        loader: 'url-loader',  // Only 'url-loader' will be used
    }],
}),
```

The following example shows how you can use the inline option in your project:

```js
// Include SVGs with '.inline' suffix
withSVG({
    include: /\.inline\./,
    inline: true,
}),

// Exclude SVGs with '.inline' suffix
withSVG({
    exclude: /\.inline\./,
}),
```

**Keep in mind**, when you opt in for the inline output, the CSS classes in your SVG **will be uniquified**, and you must be careful when selecting them. For example, using an attribute selector, as shown in the following snippet:

```css
/* Selecting an svg file with the original filename 'header-svg-inline.svg' */
[class^=header-svg-inline] {
    /* ... */
}
```

### 3D

This plugin is meant to handle **3d** files, and tests the file types `.obj`, `.mtl`, `.fnt`, `.gltf` and `.glb`.

It's not possible to know the size of most of these files when you download them, which is useful to show some kind of progress bar. The server delivers them compressed, using gzip or brotli, meaning the response does not contain the `Content-Length` header. To circumvent this problem, we use an internal loader that returns the filesize as well as its url.

An example of the returned object for `example.glb` would be:

```js
import example from './example.glb'

{
  src: '/somewhere/example.glb', // URL of the file
  size: 1024,                    // File size in bytes
}
```

### JSON5

This plugin is meant to handle **JSON5** files (`.json5`).

## Tests

Any parameter passed to the `test` command is passed down to Jest.

```sh
$ npm t
$ npm t -- --watch  # To run watch mode
```

## License

Released under the [MIT License](https://opensource.org/licenses/mit-license.php).