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