UNPKG

19.1 kBMarkdownView Raw
1<!-- Title -->
2<h1 align="center">
3👋 Welcome to <br/><code>@expo/webpack-config</code>
4</h1>
5
6<!-- Header -->
7
8<p align="center">
9 <b>Webpack config that's optimized for running universal React and react-native-web projects</b>
10 <br/>
11 <br/>
12 <a aria-label="Circle CI" href="https://circleci.com/gh/expo/expo-cli/tree/master">
13 <img alt="Circle CI" src="https://flat.badgen.net/circleci/github/expo/expo-cli?label=Circle%20CI&labelColor=555555&icon=circleci">
14 </a>
15</p>
16
17---
18
19## [Documentation][docs]
20
21To learn more about how to use this Webpack config, check out the docs here: [Customizing the Webpack config][docs]
22
23### Contributing to the docs
24
25- [Documentation for the master branch][docs-latest]
26- [Documentation for the latest stable release][docs]
27
28## API
29
30Running `expo customize:web` will generate this default config in your project.
31
32```js
33const createExpoWebpackConfigAsync = require('@expo/webpack-config');
34
35module.exports = async function(env, argv) {
36 const config = await createExpoWebpackConfigAsync(env, argv);
37 // Customize the config before returning it.
38 return config;
39};
40```
41
42## Types
43
44### `Environment`
45
46The main options used to configure how `@expo/webpack-config` works.
47
48| name | type | default | description |
49| --------------------------- | --------------------------------------- | ----------- | -------------------------------------------------------------------- |
50| `projectRoot` | `string` | required | Root of the Expo project. |
51| `https` | `boolean` | `false` | Should the dev server use https protocol. |
52| `offline` | `boolean` | `false` | Passing `true` will enable offline support and add a service worker. |
53| `mode` | `Mode` | required | The Webpack mode to bundle the project in. |
54| `platform` | [`ExpoPlatform`](#ExpoPlatform) | required | The target platform to bundle for. |
55| `pwa` | `boolean` | `true` | Generate the PWA image assets in production mode. |
56| `babel` | [`ExpoBabelOptions`](#ExpoBabelOptions) | `undefined` | Control how the default Babel loader is configured. |
57| `removeUnusedImportExports` | `boolean` | `false` | Enables advanced tree-shaking with deep scope analysis. |
58
59### `Environment` internal
60
61| name | type | default | description |
62| ----------- | ------------ | ----------- | ------------------------------------------------------------------ |
63| `config` | `ExpoConfig` | `undefined` | The Expo project config, this should be read using `@expo/config`. |
64| `locations` | `FilePaths` | `undefined` | Paths used to locate where things are. |
65
66### `ExpoPlatform`
67
68| type | description |
69| ---------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
70| `'ios' | 'android' | 'web' | 'electron'` | The target platform to bundle for. Native platforms are experimental and require a special native runtime. |
71
72### `ExpoBabelOptions`
73
74Control how the default Babel loader is configured.
75
76| name | type | default | description |
77| -------------------------------------- | ---------- | ----------- | ------------------------------------------------------------------------- |
78| `dangerouslyAddModulePathsToTranspile` | `string[]` | `undefined` | Add the names of node_modules that should be included transpilation step. |
79
80## Guides
81
82### PWAs
83
84- See the docs for [`expo-pwa`](../pwa) to learn more about creating the assets manually.
85- Disable automatic PWA generation with `expo build:web --no-pwa`.
86- `expo build:web` will automatically skip any PWA asset that's already linked in the project's local `web/index.html`.
87- Having sharp CLI installed globally will speed up asset generation, if it's not installed, Jimp will be used instead.
88
89#### Chrome PWAs
90
91##### Manifest.json
92
93The `manifest.json` will be created using the values in the project's `app.config.js`:
94
95Generating the `manifest.json` will be skipped if the following exists in the project's `web/index.html`:
96
97<details><summary>Show HTML</summary>
98
99```html
100<link rel="manifest" href="..." />
101```
102
103</details>
104
105If the `icons` array is defined in your `manifest.json`, then Chrome PWA icon generation will be skipped.
106
107##### Chrome PWA Icons
108
109Icons will be generated using the file defined in your `app.config.js` under `android.icon` and it'll fallback to `icon`.
110
111<details><summary>Show manifest.json</summary>
112
113```json
114{
115 "icons": [
116 {
117 "src": "...",
118 "sizes": "144x144",
119 "type": "image/png"
120 },
121 {
122 "src": "...",
123 "sizes": "192x192",
124 "type": "image/png"
125 },
126 {
127 "src": "...",
128 "sizes": "512x512",
129 "type": "image/png"
130 }
131 ]
132}
133```
134
135</details>
136
137#### Favicons
138
139Favicons will be generated using the file defined in your `app.config.js` under `web.favicon` and it'll fallback to `icon`.
140
141Asset generation for Favicons will be individually skipped if any of the following fields exist in your `web/index.html`:
142
143<details><summary>Show HTML</summary>
144
145```html
146<link rel="icon" type="image/png" sizes="16x16" href="..." />
147<link rel="icon" type="image/png" sizes="32x32" href="..." />
148<link rel="shortcut icon" href="..." />
149```
150
151</details>
152
153#### Safari PWAs
154
155Icons will be generated using the file defined in your `app.config.js` under `ios.icon` and it'll fallback to `icon`. The splash screens look at `ios.splash` and fallback to `splash`.
156
157Asset generation for Safari PWA icons/splash screens will be individually skipped if any of the following fields exist in your `web/index.html`:
158
159##### Icons
160
161<details><summary>Show HTML</summary>
162
163```html
164<link rel="apple-touch-icon" sizes="180x180" href="..." />
165```
166
167</details>
168
169##### Splash Screens
170
171<details><summary>Show HTML</summary>
172
173```html
174<link
175 rel="apple-touch-startup-image"
176 media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
177 href="..."
178/>
179<link
180 rel="apple-touch-startup-image"
181 media="screen and (device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
182 href="..."
183/>
184<link
185 rel="apple-touch-startup-image"
186 media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
187 href="..."
188/>
189<link
190 rel="apple-touch-startup-image"
191 media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
192 href="..."
193/>
194<link
195 rel="apple-touch-startup-image"
196 media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
197 href="..."
198/>
199<link
200 rel="apple-touch-startup-image"
201 media="screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
202 href="..."
203/>
204<link
205 rel="apple-touch-startup-image"
206 media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
207 href="..."
208/>
209<link
210 rel="apple-touch-startup-image"
211 media="screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
212 href="..."
213/>
214<link
215 rel="apple-touch-startup-image"
216 media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: landscape)"
217 href="..."
218/>
219<link
220 rel="apple-touch-startup-image"
221 media="screen and (device-width: 414px) and (device-height: 736px) and (-webkit-device-pixel-ratio: 3) and (orientation: portrait)"
222 href="..."
223/>
224<link
225 rel="apple-touch-startup-image"
226 media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)"
227 href="..."
228/>
229<link
230 rel="apple-touch-startup-image"
231 media="screen and (device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)"
232 href="..."
233/>
234```
235
236</details>
237
238### Include modules
239
240You may find that you want to include universal modules that aren't part of the default modules. You can do this by customizing the Webpack config:
241
242```ts
243const createExpoWebpackConfigAsync = require('@expo/webpack-config');
244
245module.exports = async function(env, argv) {
246 const config = await createExpoWebpackConfigAsync(
247 {
248 ...env,
249 babel: {
250 dangerouslyAddModulePathsToTranspile: [
251 // Ensure that all packages starting with @evanbacon are transpiled.
252 '@evanbacon',
253 ],
254 },
255 },
256 argv
257 );
258 return config;
259};
260```
261
262**`withUnimodules`**
263
264If you're adding support to some other Webpack config like in Storybook or Gatsby you can use the same process to include custom modules:
265
266```ts
267const { withUnimodules } = require('@expo/webpack-config/addons');
268
269module.exports = function() {
270 const someWebpackConfig = {
271 /* Your custom Webpack config */
272 };
273
274 // Add Expo support...
275 const configWithExpo = withUnimodules(someWebpackConfig, {
276 projectRoot: __dirname,
277 babel: {
278 dangerouslyAddModulePathsToTranspile: [
279 // Ensure that all packages starting with @evanbacon are transpiled.
280 '@evanbacon',
281 ],
282 },
283 });
284
285 return configWithExpo;
286};
287```
288
289This method should be used instead of using the `expo.web.build.babel.include` field of the `app.json`.
290
291### Modify the babel loader
292
293If you want to modify the babel loader further, you can retrieve it using the helper method `getExpoBabelLoader` like this:
294
295```ts
296const createExpoWebpackConfigAsync = require('@expo/webpack-config');
297const { getExpoBabelLoader } = require('@expo/webpack-config/utils');
298
299module.exports = async function(env, argv) {
300 const config = await createExpoWebpackConfigAsync(env, argv);
301 const loader = getExpoBabelLoader(config);
302 if (loader) {
303 // Modify the loader...
304 }
305 return config;
306};
307```
308
309### Service workers
310
311Service workers are great for emulating native functionality, but they can also lead to a lot of confusion so they are opt-in only (starting in Expo SDK 39 and greater) in this Webpack config. To enable the default workbox plugin pass the options `{ offline: true }` to the creator method.
312
313#### How Expo service workers ... work
314
315By default Expo web has a two part service worker. The first part `web/expo-service-worker.js` setups up optional features of the Expo SDK like Notifications. The second part `web/service-worker.js` is generated by [Workbox][workbox] and manages the offline support.
316
317The entry point for the service workers is a file called: [`register-service-worker.js`](./web-default/register-service-worker.js). This file gets copied to your static folder and registered in Webpack's `entry` property (which is why you don't see it referenced in `index.html`).
318
319#### Extending the service worker
320
321If you'd like to add extra functionality, you can simply:
322
323- Eject the Webpack config: `expo customize:web`
324 - Select `web/expo-service-worker.js`
325- Modify the `web/expo-service-worker.js` however you'd like!
326
327#### Fully disabling the service worker
328
329This can have some unfortunate side-effects as application libraries like expo-notifications may expect the SW to exist. Proceed with caution.
330
331- Eject the Webpack config: `expo customize:web`
332 - Select `webpack.config.js`
333- Modify the `webpack.config.js`:
334
335```js
336const createExpoWebpackConfigAsync = require('@expo/webpack-config');
337
338module.exports = async function(env, argv) {
339 // Set offline to `false`
340 const config = await createExpoWebpackConfigAsync({ ...env, offline: false }, argv);
341 return config;
342};
343```
344
345- This will do the following:
346 - Skip registering [`register-service-worker.js`](./web-default/register-service-worker.js) in the Webpack config `entry`.
347 - Skip including the [Webpack Workbox plugin][workbox] and creating the `web/service-worker.js`.
348 - Skip including the [`web/expo-service-worker.js`](./web-default/expo-service-worker.js)
349
350[workbox]: https://developers.google.com/web/tools/workbox
351
352## Environment Variables
353
354- `EXPO_WEBPACK_DEFINE_ENVIRONMENT_AS_KEYS`: Should the define plugin explicitly set environment variables like `process.env.FOO` instead of creating an object like `proces.env: { FOO }`. Defaults to `false`. Next.js uses this to prevent overwriting injected environment variables.
355- `IMAGE_INLINE_SIZE_LIMIT`: By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images. This is only used in production.
356- `EXPO_WEBPACK_FAST_REFRESH`: Enable experimental fast refresh in development mode.
357
358## Exports
359
360### addons
361
362For adding features to an existing Webpack config.
363
364#### `withUnimodules`
365
366```js
367import { withUnimodules } from '@expo/webpack-config/addons';
368```
369
370Wrap your existing webpack config with support for Unimodules (Expo web). ex: **Storybook** `({ config }) => withUnimodules(config)`
371
372**params**
373
374- `webpackConfig: AnyConfiguration = {}` Optional existing Webpack config to modify.
375- `env: InputEnvironment = {}` Optional [`Environment`][#environment] options for configuring what features the Webpack config supports.
376- `argv: Arguments = {}`
377
378#### `withWorkbox`
379
380Add offline support with Workbox (`workbox-webpack-plugin`).
381
382```js
383import { withWorkbox } from '@expo/webpack-config/addons';
384```
385
386#### `withOptimizations`
387
388```js
389import { withOptimizations } from '@expo/webpack-config/addons';
390```
391
392#### `withAlias`
393
394Apply aliases to a Webpack config.
395
396```js
397import { withAlias } from '@expo/webpack-config/addons';
398```
399
400#### `withDevServer`
401
402```js
403import { withDevServer } from '@expo/webpack-config/addons';
404```
405
406#### `withNodeMocks`
407
408```js
409import { withNodeMocks } from '@expo/webpack-config/addons';
410```
411
412#### `withEntry`
413
414```js
415import { withEntry } from '@expo/webpack-config/addons';
416```
417
418#### `withTypeScriptAsync`
419
420```js
421import { withTypeScriptAsync } from '@expo/webpack-config/addons';
422```
423
424### env
425
426Getting the config, paths, mode, and various other settings in your environment.
427
428#### `getConfig`
429
430```js
431import { getConfig } from '@expo/webpack-config/env';
432```
433
434#### `getMode`
435
436```js
437import { getMode } from '@expo/webpack-config/env';
438```
439
440#### `validateEnvironment`
441
442```js
443import { validateEnvironment } from '@expo/webpack-config/env';
444```
445
446#### `getAliases`
447
448```js
449import { getAliases } from '@expo/webpack-config/env';
450```
451
452#### `getPaths`
453
454```js
455import { getPaths } from '@expo/webpack-config/env';
456```
457
458#### `getPathsAsync`
459
460```js
461import { getPathsAsync } from '@expo/webpack-config/env';
462```
463
464#### `getServedPath`
465
466```js
467import { getServedPath } from '@expo/webpack-config/env';
468```
469
470#### `getPublicPaths`
471
472```js
473import { getPublicPaths } from '@expo/webpack-config/env';
474```
475
476#### `getProductionPath`
477
478```js
479import { getProductionPath } from '@expo/webpack-config/env';
480```
481
482#### `getAbsolute`
483
484```js
485import { getAbsolute } from '@expo/webpack-config/env';
486```
487
488#### `getModuleFileExtensions`
489
490```js
491import { getModuleFileExtensions } from '@expo/webpack-config/env';
492```
493
494### loaders
495
496The module rules used to load various files.
497
498#### `imageLoaderRule`
499
500```js
501import { imageLoaderRule } from '@expo/webpack-config/loaders';
502```
503
504This is needed for webpack to import static images in JavaScript files.
505"url" loader works like "file" loader except that it embeds assets smaller than specified limit in bytes as data URLs to avoid requests.
506A missing `test` is equivalent to a match.
507
508#### `fallbackLoaderRule`
509
510```js
511import { fallbackLoaderRule } from '@expo/webpack-config/loaders';
512```
513
514"file" loader makes sure those assets get served by WebpackDevServer.
515When you `import` an asset, you get its (virtual) filename.
516In production, they would get copied to the `build` folder.
517This loader doesn't use a "test" so it will catch all modules
518that fall through the other loaders.
519
520#### `styleLoaderRule`
521
522```js
523import { styleLoaderRule } from '@expo/webpack-config/loaders';
524```
525
526Default CSS loader.
527
528### plugins
529
530```js
531import /* */ '@expo/webpack-config/plugins';
532```
533
534Custom versions of Webpack Plugins that are optimized for use with native React runtimes.
535
536#### `ExpoDefinePlugin`
537
538```js
539import { ExpoDefinePlugin } from '@expo/webpack-config/plugins';
540```
541
542Required for `expo-constants` https://docs.expo.io/versions/latest/sdk/constants/.
543This surfaces the `app.json` (config) as an environment variable which is then parsed by `expo-constants`.
544
545#### `ExpoHtmlWebpackPlugin`
546
547```js
548import { ExpoHtmlWebpackPlugin } from '@expo/webpack-config/plugins';
549```
550
551Generates an `index.html` file with the <script> injected.
552
553#### `ExpoInterpolateHtmlPlugin`
554
555```js
556import { ExpoInterpolateHtmlPlugin } from '@expo/webpack-config/plugins';
557```
558
559Add variables to the `index.html`.
560
561### utils
562
563Tools for resolving fields, or searching and indexing loaders and plugins.
564
565#### `resolveEntryAsync`
566
567```js
568import { resolveEntryAsync } from '@expo/webpack-config/utils';
569```
570
571## What it does not do
572
573- **Gzip compression:** This was supported in beta but later removed in favor of hosting providers like [Now](http://now.sh/) and [Netlify](https://www.netlify.com/) automatically compressing files in the server.
574
575## License
576
577The Expo source code is made available under the [MIT license](LICENSE). Some of the dependencies are licensed differently, with the BSD license, for example.
578
579<!-- Footer -->
580
581---
582
583<p>
584 <a aria-label="sponsored by expo" href="http://expo.io">
585 <img src="https://img.shields.io/badge/Sponsored_by-Expo-4630EB.svg?style=for-the-badge&logo=EXPO&labelColor=000&logoColor=fff" target="_blank" />
586 </a>
587 <a aria-label="expo webpack-config is free to use" href="/LICENSE" target="_blank">
588 <img align="right" alt="License: MIT" src="https://img.shields.io/badge/License-MIT-success.svg?style=for-the-badge&color=33CC12" target="_blank" />
589 </a>
590</p>
591
592[docs]: https://docs.expo.io/guides/customizing-webpack/
593[docs-latest]: https://github.com/expo/expo/blob/master/docs/pages/versions/unversioned/guides/customizing-webpack.md