ctrlplusb / code-split-component Goto Github PK
View Code? Open in Web Editor NEWDeclarative code splitting for your Wepback bundled React projects, with SSR support.
License: ISC License
Declarative code splitting for your Wepback bundled React projects, with SSR support.
License: ISC License
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.
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.
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.
Proposal:
import { CodeSplit } from 'code-split-component';
<CodeSplit module={require('../Foo')}>
{ Foo => Foo && <Foo /> }
</CodeSplit>
chunkName
still avail, but optional.
I have been writing loads of unit tests and have uncovered all sorts of bugs.
Just pinging an update here so people know I am working on things.
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?
Hi have you some kind of update to replace React.PropTypes in favor of 'prop-types' module?
https://facebook.github.io/react/warnings/dont-call-proptypes.html
Regards,
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
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.
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());
Yarn will fail if version 6.9.1 is installed. You could either use ^ (don't forget to adapt for 7.x.x) or remove the requirement.
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?
Workaround is to disable code splitting via the Babel plugin for development mode.
Need to add this to the docs.
Wrong repository. sorry.
Next beta of Webpack 2.1 is introducing support for the new TC-3 agreed import()
syntax.
See: https://github.com/tc39/proposal-dynamic-import
I think the code split logic could benefit from the improvements made there over the usage of System.import
.
npm WARN [email protected] requires a peer of serialize-javascript@^1.3.0 but none was installed.
Hello! Running into an issue whereby any CSS files imported via import './styles.css'
are being mishandled by the CodeSplit
component. Here is a Gist of my setup, could definitely use some help here: https://gist.github.com/TylerK/0b6e5464403846497558b580d9f62b12
Everything else is working perfectly though! :)
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.
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.
Nice to haves.
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.
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.
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
.
I want to try this out, but it seems to require using React Router 4, which is still in alpha. Can I use RR3 instead?
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.
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?
I have successfully implemented a brand new library that completely replaces this one. It provides all of the features, including support for React Hot Loader without having to run any workarounds and or additional Webpack/Babel plugins.
Check it out here:
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} />
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.