Arunoda Susiripala, de MeteorJS à Next.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812687/rennesjs.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812710/susiripala.png)
Disclaimer !
MeteorJS
Brièvement
Réconcilier client/serveur
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812735/schema-meteor.png)
Déploiement
~ meteor deploy your-app.com --settings production-settings.json
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812779/kadira-logo-light.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812784/kadira-tool.png)
Contributions
- Meteor-up
- Flow-router
- Meteor hacks (SSR ...)
- ...
Le 30/12/2016 ...
Kadira is a 100 per cent bootstrapped company from my personal funds.
[...]
We were pretty successful with Meteor, but the market of Meteor apps was pretty small for us.
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3812873/storybook.png)
![](https://storybooks.js.org/f13d28a72b67d2862e10ca5df0f453b3.gif)
![](https://cloud.githubusercontent.com/assets/13041/19686250/971bf7f8-9ac0-11e6-975c-188defd82df1.png)
Universal JS Application
That situation was really no better than, say, PHP's. In many ways, PHP was actually more suited for the "server rendering of HTML" job
NEXTJs
- ReactJS
- SSR
- Automatic code splitting
- Zero setup
Installation
~ yarn create next-app my-app
~ cd my-app
~ yarn next
Yarn > 0.25
~ npm install -g create-next-app
~ create-next-app my-app
~ cd my-app
~ npm run dev
NPM
pages/index.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813365/Capture_d_e_cran_2017-05-17_a__16.14.12.png)
pages/rennes.js
export default () => <h1>What a new Page !</h1>;
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813450/Capture_d_e_cran_2017-05-17_a__16.28.47.png)
A partir d'une url, seul le code nécessaire est chargé
Configuration des Metas
import Head from 'next/head';
export default ({ title = 'This is the default title' }) => (
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
);
Query Param
export default ({ url: { query: { id } } }) => (
<div>
<h1>Mon identifiant est : {id}</h1>
</div>
);
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813547/Capture_d_e_cran_2017-05-17_a__16.47.58.png)
/sub/path
Path Param
{
"name": "create-next-example-app",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "^2.3.1",
"react": "^15.5.4",
"react-dom": "^15.5.4"
}
}
{
"name": "create-next-example-app",
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
"dependencies": {
"next": "^2.3.1",
"react": "^15.5.4",
"react-dom": "^15.5.4"
}
}
Un peu de prog côté serveur
package.json
Path Param
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const pathMatch = require('path-match');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const route = pathMatch();
const match = route('/rennesjs/:param');
app.prepare().then(() => {
createServer((req, res) => {
const { pathname, query } = parse(req.url, true);
const params = match(pathname);
if (params === false) {
handle(req, res);
return;
}
app.render(req, res, '/sub/path', Object.assign(params, query));
}).listen(3000, err => {
if (err) throw err;
console.log('> Ready on http://localhost:3000');
});
});
server.js
Path Param
export default ({ url: { query: { id, param } } }) => (
<div>
<h1>Mon identifiant est : {id} et mon chemin est : {param}</h1>
</div>
);
/pages/sub/path.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813696/Capture_d_e_cran_2017-05-17_a__17.14.58.png)
Links
import Link from 'next/link';
export default ({ url: { query: { id, param } } }) => (
<div>
<h1>Mon identifiant est : {id} et mon chemin est : {param}</h1>
<Link href="/rennesjs">
<a title="Retour à Rennes Js">
plip
</a>
</Link>
</div>
);
/pages/sub/path.js
Prefetch
<Link prefetch href="/rennesjs">
<a title="Retour à Rennes Js">
plip
</a>
</Link>
import Router from 'next/router'
...
{
Router.prefetch('/rennesjs')
}
Layouts
import Link from 'next/link';
import Head from 'next/head';
export default ({ children, title = 'This is the default title' }) => (
<div>
<Head>
<title>{title}</title>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
</Head>
<header>
<nav>
<Link href="/"><a>Home</a></Link> |
<Link href="/rennesjs"><a>Rennes JS</a></Link> |
</nav>
</header>
{children}
<footer>
Je suis en bas mais je suis bien
</footer>
</div>
);
/components/layout.js
Layouts
import Link from 'next/link';
import Layout from '../../components/layout';
export default ({ url: { query: { id, param } } }) => (
<Layout>
<h1>Mon identifiant est : {id} et mon chemin est : {param}</h1>
<Link href="/rennesjs">
<a title="Retour à Rennes Js">
plip
</a>
</Link>
</Layout>
);
/pages/sub/path.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813745/Capture_d_e_cran_2017-05-17_a__17.23.37.png)
Data
import Link from 'next/link';
import Layout from '../../components/layout';
import axios from 'axios';
const path = ({ url: { query: { id, param } }, avatar }) => (
<Layout>
<h1>Mon identifiant est : {id} et mon chemin est : {param}</h1>
<Link href="/rennesjs">
<a title="Retour à Rennes Js">
plip
</a>
</Link>
<br />
<img src={avatar} width="60px" />
</Layout>
);
path.getInitialProps = async ({ req }) => {
const res = await axios.get('https://api.github.com/users/mlecoq/events');
return { avatar: res.data[0].actor.avatar_url };
};
export default path;
/pages/sub/path.js
Data
/pages/sub/path.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3813882/Capture_d_e_cran_2017-05-17_a__17.44.53.png)
State (Redux)
~ yarn add redux
~ yarn add react-redux
~ yarn add next-redux-wrapper
State (Redux)
import { createStore } from 'redux';
export const actionTypes = {
ADD: 'ADD',
REMOVE: 'REMOVE',
};
const reducer = (state = { count: 0 }, action) => {
switch (action.type) {
case actionTypes.ADD:
return { ...state, count: state.count + 1 };
case actionTypes.REMOVE:
return { ...state, count: state.count - 1 };
default:
return state;
}
};
export const makeStore = initialState => {
return createStore(reducer, initialState);
};
export function addCount() {
return { type: actionTypes.ADD };
}
export function removeCount() {
return { type: actionTypes.REMOVE };
}
Store
State (Redux)
import withRedux from 'next-redux-wrapper';
import Link from 'next/link';
import { bindActionCreators } from 'redux';
import { makeStore, addCount } from '../store/store';
const AddCounter = ({ add, count }) => (
<div>
<h1>Compteur: <span>{count}</span></h1>
<button onClick={add}>Plus !</button>
<br />
<Link href="/remove">Moins</Link>
</div>
);
const mapStateToProps = ({ count }) => ({ count });
const mapDispatchToProps = dispatch => ({
add: bindActionCreators(addCount, dispatch),
});
export default withRedux(makeStore, mapStateToProps, mapDispatchToProps)(
AddCounter,
);
pages/add.js
State (Redux)
import withRedux from 'next-redux-wrapper';
import Link from 'next/link';
import { bindActionCreators } from 'redux';
import { makeStore, addCount } from '../store/store';
const AddCounter = ({ add, count }) => (
<div>
<h1>Compteur: <span>{count}</span></h1>
<button onClick={add}>Plus !</button>
<br />
<Link href="/remove">Moins</Link>
</div>
);
AddCounter.getInitialProps = ({ store }) => {
store.dispatch(addCount());
};
const mapStateToProps = ({ count }) => ({ count });
const mapDispatchToProps = dispatch => ({
add: bindActionCreators(addCount, dispatch),
});
export default withRedux(makeStore, mapStateToProps, mapDispatchToProps)(
AddCounter,
);
pages/add.js
Et si je préfère Vue
![](http://imgur.com/V4LtoII.png)
Deploiement avec now
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3814146/Capture_d_e_cran_2017-05-17_a__18.43.37.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/492582/images/3814173/Capture_d_e_cran_2017-05-17_a__18.59.07.png)
![](https://nodejs.org/static/images/logos/nodejs-new-black.png)
![](http://www.duchess-france.org/wp-content/uploads/2015/06/docker.png)
Site Statique
Next 3.0
- Dynamic Import & Export
- Export en site statique
import dynamic from 'next/dynamic'
const DynamicComponent1 = dynamic(import('../components/hello1'))
const DynamicComponent2 = dynamic(import('../components/hello2'))
export default () => (
<div>
<Header />
<DynamicComponent />
<p>HOME PAGE is here!</p>
</div>
)
Autres projets oss de Zeit
![](https://raw.githubusercontent.com/zeit/art/31913be3107827adf10e1f491ec61480f63e19af/micro/logo.png)
Micro Service
Hyper
![](https://pbs.twimg.com/media/C-41hAtWsAAep8b.jpg)
Pkg
pkg . --targets node6-macos-x64
Arunoda Susiripala, de MeteorJS à Next.js
By Mickael Lecoq
Arunoda Susiripala, de MeteorJS à Next.js
- 2,351