GithubHelp home page GithubHelp logo

ctrlplusb / code-split-component Goto Github PK

View Code? Open in Web Editor NEW
116.0 116.0 6.0 169 KB

Declarative code splitting for your Wepback bundled React projects, with SSR support.

License: ISC License

JavaScript 100.00%

code-split-component's People

Contributors

ctrlplusb avatar dlebedynskyi avatar swernerx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

code-split-component's Issues

Support use with RecordIdsPlugin (and HardSourceWebpackPlugin)

When used with RecordIdsPlugin, CodeSplit incidentally stores chunk ids in the records that when used in follow up builds leads to a small part of webpack. Used with a chunk named like vendor CodeSplit currently creates the chunk hash, 820075192, for it. When that webpack code snippet hits that id it tries to make an array of about 820075188 members, which would need more than 3.2 gigs and causes NodeJS to normally run out memory and exit with an error.

(This is related to HardSourceWebpackPlugin (mzgoddard/hard-source-webpack-plugin#51 (comment)) which uses RecordIdsPlugin to ensure module and chunk ids are immutable in relation to module and chunk identifiers.)

Right now I can think of two solutions.

  1. Cap the chunk hash ids. Possibly by applying a mod operation on the final hash to keep in a small number range.
  2. Write template plugins like https://gist.github.com/mzgoddard/f6dbbe49bc5e05e7d6ddd15fa1beb0df to inject code to record the chunk id to a map and copy over the chunk listeners before webpackJsonp is called.

The second is definitely a more involved change but removes any concern for incompatibility with RecordIds and hash collisions on chunk name.

Another note on RecordIds, it is always on, so this might be something encountered when just using webpack in watch mode without disabling the CodeSplit webpack plugin.

Prevent "loading" flashing for bundles that have already been resolved.

Update

I have done some initial testing and it's not as bad as I may have initially thought it would have been. When updating a component that contains a CodeSplit instance the CodeSplit instance won't do a double render - all the resolving is in the mounting lifecycle.

When initially mounting a CodeSplit that has modules which have already been resolved from the server the setState update -> render is so fast I couldn't notice any sort of flashing, but this needs more testing. Perhaps dropping in beefier components will yield some issues with this.

Simplify API

Proposal:

import { CodeSplit } from 'code-split-component';
<CodeSplit module={require('../Foo')}>
  { Foo => Foo && <Foo /> }
</CodeSplit>

chunkName still avail, but optional.

Cleaning up usage with react router v4

Hey,

I'm really glad I got a chance to stumble upon this project it didn't take to long to figure it out either and I was able to set up route based code splitting in the following way:

        <Match
          exactly pattern="/" component={() => (
            <CodeSplit chunkName="base" modules={{ Base: require('./layouts/Base') }}>
              { ({ Base }) => Base ? <Base /> : <div>Loading...</div> }
            </CodeSplit>
          )}
        /> 

And it now loads correct chunks for each route :) however I can't help and feel that this is a bit verbose, plus throws a coupe of errors in eslint like no-confusing-arrow for ({ Base }) => Base.. bit, and I don't want to disable it every time with a comment. I tried creating a whole new component that uses routers Match and CodeSplit, but failed, hence wanted to get your advice on this to see if it is possible to get some advice on this

Me being me and submitting this issue pre-maturely I just scrolled to the end of the read me and saw advised implementation for react router

<Match
  pattern="/about"
  render={routerProps =>
    <CodeSplit chunkName="about" modules={{ About: require('./About') }}>
      { ({ About }) => About && <About {...routerProps} /> }
    </CodeSplit>
  }
/>

Could you please explain where routerProps are coming from?

NOTICE: Holiday'ing for 3 weeks.

Some much needed family quality time.

I'll be leaving the laptop at home.

I still care, I just won't be able to reply until the 26th.

x

Feature: add a 'skipSSR' property

Some components have such heavy JavaScript powered controls, so prerendering them may frustrate a user as they will be unable to interact with the component until the scripts are loaded. In these cases wrap the component with CodeSplit and set the skipSSR prop. This will ensure that the component doesn't get prerendered on the server and will async load on client.

A nice compromise.

CommonChunksPlugin breaks build

Thanks for working on this component. It looks like it going to be very handy.
I'm running into issue on production build with uglifyjs.
It only happens for production build.

My config

//package.json
"build": "NODE_ENV=production webpack --config src/config/webpack.config.prod.js -p",
//webpack.config.prod.js
entry: {
    vendor,
    app: ['babel-polyfill', `${SRC}/styles/app.scss`, `${SRC}/client-entry.js`]
  },
module: {
    loaders: [
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        test: /\.jsx?$/,
        include: [/src/],
        loader: 'babel',
        query: {
          plugins: [
           [
              'code-split-component/babel',
              {
                disabled: false
              }
            ]
          ]
        }
      },
... 

prodConfig.module.loaders.push({
  test: /\.jsx?$/, loader: WebpackStrip.loader('console.log', 'console.debug')
});

prodConfig.plugins.push(new CodeSplitPlugin());

Gives

ERROR in vendor.ce7455f2b338600395b1.js from UglifyJs
SyntaxError: Unexpected token num «820075192», expected punc «:» [webpack/bootstrap 6f7c862bd7fb36d95dc3:55,0][vendor.ce7455f2b338600395b1.js:56,12]

for reference

// vendor has
module.exports = [
  'debug',
  'react',
  'react-dom',
  'react-helmet',
  'react-redux',
  'redux',
...
]

Have no issues without prodConfig.plugins.push(new CodeSplitPlugin());

CodeSplit doesn't work with nested routes in RR4

I have setup nested routes for my app, and i got this error when navigate to it if I use CodeSplit inside render props of Match.

usage:

<Match
  pattern={`${pathname}/accept`}
  render={routerProps =>
    <CodeSplit chunkName="payment" modules={{ AccPage: require('./accept') }}>
      { ({ AccPage }) => AccPage && <AccPage {...routerProps} />
  }
/>

Error in console:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `Subscriber`.
printWarning @ __dev_vendor_dll__.js:4694
__dev_vendor_dll__.js:4647 Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of `Subscriber`.
    at invariant (__dev_vendor_dll__.js:4640)
    at ReactCompositeComponentWrapper.instantiateReactComponent [as _instantiateReactComponent] (__dev_vendor_dll__.js:35856)
    at ReactCompositeComponentWrapper._updateRenderedComponent (__dev_vendor_dll__.js:33666)
    at ReactCompositeComponentWrapper._performComponentUpdate (__dev_vendor_dll__.js:33629)
    at ReactCompositeComponentWrapper.updateComponent (__dev_vendor_dll__.js:33550)
    at ReactCompositeComponentWrapper.receiveComponent (__dev_vendor_dll__.js:33452)
    at Object.receiveComponent (__dev_vendor_dll__.js:7576)
    at ReactCompositeComponentWrapper._updateRenderedComponent (__dev_vendor_dll__.js:33659)
    at ReactCompositeComponentWrapper._performComponentUpdate (__dev_vendor_dll__.js:33629)
    at ReactCompositeComponentWrapper.updateComponent (__dev_vendor_dll__.js:33550)

Any idea how to make this work guys? Without codesplit it works perfectly?

Getting "An error occurred whilst attempting to rehydrate code-split-component"

Hello. First congratulation for this amazing library.

I am getting this error in the production build with SSR.

The full strack trace:

An error occurred whilst attempting to rehydrate code-split-component. TypeError: Cannot read property 'call' of undefined
    at __webpack_require__ (http://localhost:8000/vendor.4236bf86234939fda7e5.js:51:29)
    at resolveModule (http://localhost:8000/vendor.4236bf86234939fda7e5.js:28709:38)
    at Array.map (native)
    at http://localhost:8000/vendor.4236bf86234939fda7e5.js:28714:23 TypeError: Cannot read property 'call' of undefined
    at __webpack_require__ (http://localhost:8000/vendor.4236bf86234939fda7e5.js:51:29)
    at resolveModule (http://localhost:8000/vendor.4236bf86234939fda7e5.js:28709:38)
    at Array.map (native)
    at http://localhost:8000/vendor.4236bf86234939fda7e5.js:28714:23

It appears to be something related to the JSONp request.

My code:

Root.js

import React from 'react';
import { Match } from 'react-router';
import { CodeSplit } from 'code-split-component';

const Root = () => (
  <div className="container">
    <h1>Welcome to App</h1>

    <Match
      exactly
      pattern="/"
      render={routerProps =>
        <CodeSplit chunkName="index" modules={{ Index: require('./Index') }}>
          { ({ Index }) => Index && <Index {...routerProps} /> }
        </CodeSplit>}
    />
  </div>
);

export default Root;

.babelrc

{
  "presets": ["es2015", "stage-3", "react"],
  "env": {
    "development": {
      "plugins": [
        ["code-split-component/babel", {
          "disabled": true
        }],
        "react-hot-loader/babel"
      ]
    },
    "production": {
      "plugins": [
        "code-split-component/babel"
      ]
    }
  }
}

webpack.config.server.js

[...]
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel',
        query: {
          presets: [
            'react',
            'es2015',
            'stage-0',
          ],
          plugins: [
            [
              'babel-plugin-webpack-loaders',
              { config: './webpack.config.babel.js', verbose: false }
            ],
            [
              'code-split-component/babel',
              { mode: 'server' }
            ]
          ]
        },
      },
[...]

webpack.config.prod.js

[...]

  plugins: [
    new ManifestPlugin(),
    new CodeSplitWebpackPlugin(),
    new webpack.optimize.CommonsChunkPlugin({
      name: 'vendor',
      minChunks: Infinity,
      filename: '[name].[chunkhash].js',
    }),
  ]

server.js

  const codeSplitContext = createRenderContext();

  const content = renderToString(
    <CodeSplitProvider context={codeSplitContext}>
      <ServerRouter location={req.url} context={reactRouterContext}>
        <Root />
      </ServerRouter>
    </CodeSplitProvider>,
  );

client.js

function renderApp(TheApp) {
  rehydrateState().then(codeSplitState =>
    render(
      <ReactHotLoader>
        <CodeSplitProvider state={codeSplitState}>
          <BrowserRouter>
            <TheApp />
          </BrowserRouter>
        </CodeSplitProvider>
      </ReactHotLoader>,
    mountNode),
  );
}

package.json dependencies

"dependencies": {
    "babel-plugin-add-module-exports": "^0.2.1",
    "bootstrap-sass": "^3.3.7",
    "code-split-component": "2.0.0-alpha.5",
    "express": "^4.14.0",
    "extract-text-webpack-plugin": "^1.0.1",
    "json-loader": "^0.5.4",
    "react": "^15.4.2",
    "react-bootstrap": "^0.30.7",
    "react-dom": "^15.4.2",
    "react-router": "4.0.0-alpha.6",
    "serialize-javascript": "^1.3.0",
    "webpack-vendor-chunk-plugin": "^1.0.0"
  },
  "devDependencies": {
    "babel-cli": "^6.18.0",
    "babel-core": "^6.21.0",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^6.2.10",
    "babel-plugin-webpack-loaders": "^0.8.0",
    "babel-preset-env": "^1.1.8",
    "babel-preset-es2015": "^6.18.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-stage-3": "^6.17.0",
    "chunk-manifest-webpack-plugin": "^1.0.0",
    "cross-env": "^3.1.4",
    "css-loader": "^0.26.1",
    "cssnano": "^3.10.0",
    "empty": "^0.10.1",
    "eslint": "^3.13.1",
    "eslint-config-airbnb": "^14.0.0",
    "eslint-plugin-flowtype": "^2.30.0",
    "eslint-plugin-import": "^2.2.0",
    "eslint-plugin-jsx-a11y": "^3.0.2",
    "eslint-plugin-react": "^6.9.0",
    "file-loader": "^0.9.0",
    "flow-bin": "^0.37.4",
    "node-sass": "^4.3.0",
    "postcss-cssnext": "^2.9.0",
    "postcss-focus": "^1.0.0",
    "postcss-loader": "^1.2.2",
    "postcss-reporter": "^3.0.0",
    "react-hot-loader": "^3.0.0-beta.2",
    "rimraf": "^2.5.4",
    "sass-loader": "^4.1.1",
    "sass-resources-loader": "^1.2.0-beta.1",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.14.0",
    "webpack-dev-middleware": "^1.9.0",
    "webpack-externals-plugin": "^1.0.0",
    "webpack-hot-middleware": "^2.15.0",
    "webpack-manifest-plugin": "^1.1.0"
  }

I wrote this very quickly, so if you need more information, just ask me.

I really want to use this component. It helps a lot.

Thank you.

Road to v2

An alpha is up and running within react-universally. It is tons better, but I would like us to finish all of the below before releasing an official v2.

  • Test on webpack v1 and v2
  • Guard that the plugins are disabled for a module.hot environment.
  • Add example(s)
  • Higher test coverage
  • API refactor/simplification parses
  • Clean up / document code.
  • Documentation
  • A long standing issue-free alpha/beta version.

Nice to haves.

  • Add optimised CodeSplitMatch component for react-router 4
  • react-router 3 story

An error occurred whilst attempting to rehydrate code-split-component. Error: Loading chunk 2 on first load

Hi,

Not sure why, but on the initial load of my production website, I get:

An error occurred whilst attempting to rehydrate code-split-component. Error: Loading chunk 2 failed.
    at HTMLScriptElement.n (index-25650bf….js:1) Error: Loading chunk 2 failed.
    at HTMLScriptElement.n (https://gzk-klinik.herokuapp.com/client/index-25650bfe9bda9f0d4e30.js:1:507)

You can see it live here: https://gzk-klinik.herokuapp.com. Please notice, this is only for the first load, I guess afterwards the chunks are cached and the problem disappears. This is alpha 5 btw.

Any idea?

ps. A colleague just informed me he's got similar problems An error occurred whilst attempting to rehydrate code-split-component. TypeError: Cannot read property 'call' of undefined while using code-split component in production, but only on safari and constantly. I wonder if this masks another underlying problem or if code-split-component is causing the problem.

React Hot Loader support

Ok, so it looks like webpack HMR comparability is ok, but React Hot Loader not so. I get full page app re-renders, ala standard hot module reloading. I have some intuition for a "fix". Hopefully it works. Less config complexity will be nice.

Suggestion: User System.import/require.insure

Currently you have to use code split as

<Match
  pattern="/about"
  render={routerProps =>
    <CodeSplit chunkName="about" modules={{ About: require('./About') }}>
      { ({ About }) => About && <About {...routerProps} /> }
    </CodeSplit>
  }
/>

this makes require call directly in code. Instead it would be great to use more traditional require.ensure or webpack 2 System.import.

SSR and RR4 implementation is not optimal.

I wouldn't recommend using this component in an SSR environment or even on RR4 like I have shown. It works, but isn't optimal.

I have a fully fledged solution in the works.

Uncaught error during development build (with correct hmr setup)

I've ensured to set up my webpacks dev config accordingly to account for hot module issues related to the plugin, however I still get error during my dev build:

CodeSplit.js:103 Uncaught Error:

line that it refers to is

100 if (typeof modules === 'function') {
101        // Async modules.
102       if (true) {
>103         throw new Error(HMR_NOT_SUPPORTED);
104        }

My plugin setup includes:

new CodeSplitWebpackPlugin({
   disabled: process.env.NODE_ENV === 'development'
})

and

{
  "presets": ["react-app"],
  "plugins": ["code-split-component/babel"],
  "env": {
    "development": {
      "plugins": [
        ["code-split-component/babel", { "disabled": true }]
      ]
    }
  }
}

As well as I logged out my environment and it is indeed set to development, not sure if this is potential bug or I am missing something obvious? Looking at the networking tab I can see that I'm only including one bundle.js file, so it seems to be loading everything async?

How to use without <CodeSplit> being a Wrapper ?

Is there a way to return the Actual Component instead of Wrapping the component within because when using isomorphic-relay-router the Component has to be a RelayContainer

So Instead of

  <CodeSplit chunkName="home" modules={{ Home: require('./components/App/Home') }}>
     { ({ Home }) => Home && <Home {...routerProps} /> }
   </CodeSplit>

Something like this

const Home = CodeSplit({chunkName="home", modules={{ Home: require('./components/App/Home') }});
return <Home {...routerProps} />

Sync mode names with webpacks targets

Webpack uses either node or web as a target for typical SSR apps. I figure it would make sense to sync the options in this plugin to use the same convention.

Naming is already hard enough and we use a ton of tools nowadays. We should align on some basics patterns to not confuse new users.

Docs: https://webpack.js.org/configuration/target/#target

BTW: I am in progress of changing this in advanced-boilerplate and prepublish-lib, too.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.