Create-react-app: Split vendor and app into separate files

Created on 18 May 2017  Â·  31Comments  Â·  Source: facebook/create-react-app

NOT AN ISSUE but a feature request.
imo, it would be beneficial for splitting the js bundle into app and vendor files.
My app code keeps changing but vendor dependencies rarely change. splitting into two files will be a lot beneficial for long term caching.

If this interests, i will be more than happy to make a pull request for this.

claimed proposal

Most helpful comment

Okay i think my way of splitting vendor is quite different.
i just had a look to the fore mentioned pull request. it deals with dll (which i still not too familiar with)

webpack is super awesome
the commons chunk plugin takes can take a function, thus we can automatically determine all the vendors by checking if the import belongs to node_modules folder or not.

// this assumes your vendor imports exist in the node_modules directory
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: module => module.context && module.context.indexOf('node_modules') !== -1
}),

All 31 comments

Yeah I agree it’s a good idea.

@viankakrisna did some work in #1651 but it’s pretty complicated. Maybe we can start with something simpler. For now I would be open to taking the following implementation:

  • src/index.js stays the main entry point
  • If src/vendor.js exists, then anything imported there goes into a separate vendor bundle

Okay i think my way of splitting vendor is quite different.
i just had a look to the fore mentioned pull request. it deals with dll (which i still not too familiar with)

webpack is super awesome
the commons chunk plugin takes can take a function, thus we can automatically determine all the vendors by checking if the import belongs to node_modules folder or not.

// this assumes your vendor imports exist in the node_modules directory
new webpack.optimize.CommonsChunkPlugin({
  name: 'vendor',
  minChunks: module => module.context && module.context.indexOf('node_modules') !== -1
}),

I'm not sure this works well because some Node modules update much more often than others. I would like to keep user in control here.

ahh i see the point. got it.

@gaearon i'll try making a pull request by weekend for the way you mentioned src/index.js and src/vendor.js

Sounds good!

@gaearon actually i've moved the vendor entry point to ./src/vendor.js but no heuristics yet to enable the feature only if it exists (i could add another check in start.js and webpack config :p). I'll try to simplify it to a webpack plugin i guess.

@shrynx The common chunks plugin still runs on every build, so it does not solve the long build time for large project (can the build be cached? I actually haven't explore it ). I chose dll because then we can control when we want to build the vendor bundle.

As a side note, i haven't found a solution for this auto bundling the vendor yet. The closest one is this https://github.com/clinyong/dll-link-webpack-plugin but it requires user to use yarn.

My solution depends on the hash of vendor.js, yarn.lock (if exists), package.json, existence of the build in node_modules/.cache/vendor, and switches on prod / dev. I agree the ejected user will overwhelmed by the config right now, but i'll try to simplify it into a plugin (all help is welcome!).

@shrynx for prior discussion of long term caching, see https://github.com/facebookincubator/create-react-app/issues/210

@viankakrisna i might be mistaken, but there are two separate issues.

  • long term asset caching by browsers for vendor file.
  • caching vendor libraries during compile time, so as to reduce build time.

of course they can be solved with a common approach (like your PR), but my feature request was of browser caching and not compile time caching (definitely a relevant issue !)

@gaearon just to make sure, should i be working on vendor splitting for browser cache or for both browser cache && build time ?

Added a check for ./src/vendor.js existence here https://github.com/facebookincubator/create-react-app/pull/1651/files#diff-c0e4b3a84334c2e5d316b33e2b0d5c9bR7 It's now opt-in :).

@shrynx yeah, but for a long term caching the bundle is still generated on compile time, is it not?

1651 is solving those two issue that you have said, it's splitting the vendor and app code (solving long term caching) with it's own each build process (solving faster rebuilds). It's quite complex in the earlier iterations, because it's naively modifying webpack config without heuristics.

Right now that PR does not touch the webpack config if src/vendor.js not exists. so i think it's quite simple for ejected users (i hope).

Sorry for the silence. i had been little busy.
@viankakrisna yes, the bundle is again generated at compile time, but i can use deterministic hashes to keep it the same. Again my aim is not solving build time, but browser caching.
@gaearon a little update.
i made a demo app, with vendor and route splitting and ran build.
the first build contains two routes.
screen shot 2017-05-21 at 12 04 04
next i added one more route to the application and built it again.
screen shot 2017-05-21 at 12 04 29
the vendor file and old routes keep same hashes.

i'll send up a pull request regarding this in a while (cleaning things up). i have one concern this process always generates
one manifest file (to extract out the common runtime). As this file is usually small (< 1kb), i would prefer to inline it. any suggestions regarding this ?

That's very useful, but will old routes still keep same hashes when delete first route?

Guys, how about making /src/chunks/,

So /src/chunks/index.js has other imports:

import vendors from './vendors.js'
import utils from './utils.js'
import devtools from './devtools.js'
// e.t.c.

// vendors.js content will be separated to vendors.6fj34s78hjfg.js chunk

import React, { Component } from 'react'

import PropTypes from 'prop-types'

export {
  React,
  Component,
  PropTypes
}

//  utils.js content will be separated to utils.7645ydffj6645.js chunk
import ... from '../utils'

export {
  ...
}
//  devtools.js content will be separated to devtools.k65ffs45yyj6.js chunk
import DevTools from '../devtools'

export {
  DevTools
}
// Somwhere in app structure:

import {
  React,
  Component,
  PropTypes
} from '../../chunks/vendors'

class A extends Component {...

if /src/chunks/index.js is empty, there is no code splitting

This keeps control in user's hands and creates best practices pattern

I used this pattern in times of webpack 1.x.x

BTW I tried to use /src/vendor.js and have no code splitting (

@JustFly1984 Nothing was merged, so there is no splitting.

Can you update the status? Right now I feel like I getting need to use CRA for development and make production webpack config separate from CRA. I'm getting weird tensions in the team. One part against ejecting, another needs a build improvements. Please clarify your intentions about vendor splitting.

Another project along the same lines as AutoDllPlugin: fliphub/d-l-l

Why not this in webpack.config.prod.js:

const vendors = require('../src/vendors');

...

entry: {
  polyfills: require.resolve('./polyfills'),
  app: paths.appIndexJs,
  vendors,
},

...

plugins: [
  new webpack.optimize.CommonsChunkPlugin(/* chunkName= */ 'vendors'),
...
],

And in src/vendors.js:

module.exports = ['react', 'react-dom', ...];

I kept every thing else (with react-scripts 1.0.10) and added this and the code splitting is working

Any news on this?

I'm working on a PR

Can't wait!

2017-09-18 22:59 GMT+08:00 Ayc0 notifications@github.com:

I'm working on a PR

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebookincubator/create-react-app/issues/2206#issuecomment-330250971,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACJseSE2bm9fDtEwI6botit633eDLdK0ks5sjoVhgaJpZM4Net1O
.

I think it's done

When and how to use it in CRA?

2017-09-19 12:21 GMT+08:00 Ayc0 notifications@github.com:

I think it's done

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/facebookincubator/create-react-app/issues/2206#issuecomment-330425153,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ACJseXfvm-Tt7-CVFVrq7OyKVWayMkVUks5sj0FUgaJpZM4Net1O
.

If the PR is merged, there will be a src/vendors.js file and inside, only module.exports = ['react', 'react-dom'];

To add another vendors, you just have to fill the array with the npm module names, and if the file doesn't exist, there won't be any vendors

but if you need this feature as soon as possible, you can eject the conf, add manually this MR (and others), and if a new version of CRA includes everything you need, you'll revert the eject (just revert the commit)

They don't need to eject, they could use the release cut by @react-scripts-dangerous temporarily.

@Timer how to use this feature right now?

@ebhoren if you're willing to help test the feature, follow these instructions: https://github.com/facebookincubator/create-react-app/pull/3145#issuecomment-333220365

Was this page helpful?
0 / 5 - 0 ratings

Related issues

stopachka picture stopachka  Â·  3Comments

oltsa picture oltsa  Â·  3Comments

Evan-GK picture Evan-GK  Â·  3Comments

DaveLindberg picture DaveLindberg  Â·  3Comments

onelson picture onelson  Â·  3Comments