├── .gitignore ├── .jsbeautifyrc ├── LICENSE ├── README.md ├── bin ├── bundler │ ├── dev.js │ └── prod.js ├── clean.js └── server │ ├── hotReload.js │ └── index.js ├── config ├── webpack.dev.client.js ├── webpack.dev.server.js ├── webpack.prod.js └── webpack.shared.js ├── package.json ├── src ├── client │ └── index.tsx ├── server │ └── index.tsx └── shared │ ├── components │ ├── 404 │ │ └── 404.tsx │ ├── app.scss │ ├── app.tsx │ ├── example │ │ ├── example.css │ │ ├── example.tsx │ │ └── img │ │ │ └── react.png │ ├── footer │ │ ├── footer.scss │ │ └── footer.tsx │ ├── header │ │ ├── header.scss │ │ └── header.tsx │ ├── navbar │ │ └── navbar.tsx │ ├── single │ │ └── single.tsx │ └── welcome │ │ └── welcome.tsx │ ├── favicon.ico │ └── routes.tsx ├── tsconfig.json └── typings.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 18 | .grunt 19 | 20 | # node-waf configuration 21 | .lock-wscript 22 | 23 | # Compiled binary addons (http://nodejs.org/api/addons.html) 24 | build/Release 25 | 26 | # Dependency directory 27 | node_modules 28 | 29 | # Optional npm cache directory 30 | .npm 31 | 32 | # Optional REPL history 33 | .node_repl_history 34 | 35 | # IDEA 36 | .idea 37 | *.iml 38 | 39 | # Misc 40 | public 41 | dist 42 | src/**/*.js 43 | src/**/*.js.map 44 | src/**/*.jsx 45 | src/**/*.jsx.map 46 | 47 | # Typescript 48 | tsd.json 49 | typings 50 | -------------------------------------------------------------------------------- /.jsbeautifyrc: -------------------------------------------------------------------------------- 1 | { 2 | "brace_style": "collapse-preserve-inline", 3 | "break_chained_methods": false, 4 | "comma_first": false, 5 | "e4x": true, 6 | "end_with_newline": true, 7 | "eol": "\n", 8 | "eval_code": false, 9 | "keep_array_indentation": false, 10 | "keep_function_indentation": false, 11 | "indent_size": 4, 12 | "indent_char": " ", 13 | "indent_level": 0, 14 | "indent_with_tabs": true, 15 | "jslint_happy": false, 16 | "max_preserve_newlines": 10, 17 | "preserve_newlines": true, 18 | "space_after_anon_function": false, 19 | "space_before_conditional": false, 20 | "space_in_paren": false, 21 | "wrap_attributes": "auto", 22 | "wrap_attributes_indent_size": 4, 23 | "wrap_line_length": 0, 24 | "unescape_strings": false, 25 | 26 | "newline_between_rules": true, 27 | "selector_separator_newline": false, 28 | 29 | "extra_liners": ["head", "body", "/html"], 30 | "indent_inner_html": true, 31 | "indent_scripts": "normal", 32 | "unformatted": ["inline"] 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ayoub ADIB 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React Typescript Isomorphic Starter Kit 2 | 3 | An isomorphic React boilerplate with Typescript, Webpack (SASS/CSS loader, JSX/JS loader, File loader...), React Router, React Hot Loader and ESLint static code verification.
Become more productive and Enable shared javascript that runs on both client and server (client side + server side rendering)).
All necessary tools are set up to start up quickly your React Typescript project ! 4 | 5 |
6 | ## Getting Started 7 | 8 | To begin with this starter kit project, simply follow these steps: 9 | 10 | - [x] Clone repository: `git clone https://github.com/ayoubdev/reactjs-typescript-isomorphic-starterkit.git` 11 | - [x] Go to cloned directory and feel free to modify `package.json` information (like project name, description...): 12 | - [x] Run this cli command: `npm install` 13 | - [x] Open this URL and enjoy: `http://localhost:8080/` 14 | 15 |
16 | ## Available Commands 17 | 18 | #### For server: 19 | 20 | > **npm run server**
Launch server (by default, listening to port 8080)
21 | 22 | #### For development: 23 | 24 | > **npm run watch**
Transpile tsx/ts files, Bundle and Track changes in client and server side ressources (via Hot Module Replacement [HMR])
25 | 26 | #### For production: 27 | 28 | > **npm run build**
Transpile tsx/ts files and Bundle static resources to ./dist folder

29 | > **npm run deploy**
Build and Launch server
30 | 31 | #### Misc commands: 32 | 33 | > **npm run clean**
Delete bundler outputs (./dist folder)
34 | 35 |
36 | ## License 37 | 38 | MIT 39 | -------------------------------------------------------------------------------- /bin/bundler/dev.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var config = require("../../config/webpack.dev.server.js"); 3 | 4 | var options = { 5 | chunk: false, 6 | chunkModules: false, 7 | modules: false, 8 | source: false, 9 | chunkOrigins: false 10 | }; 11 | 12 | var compiler = webpack(config); 13 | 14 | compiler.run(function(err, stats) { 15 | if(err) 16 | return console.error(err.message); 17 | 18 | console.log(stats.toString(options)); 19 | }); 20 | -------------------------------------------------------------------------------- /bin/bundler/prod.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var ProgressPlugin = require("webpack/lib/ProgressPlugin"); 3 | var config = require("../../config/webpack.prod.js"); 4 | 5 | var compiler = webpack(config); 6 | 7 | compiler.apply(new ProgressPlugin(function(percentage, log) { 8 | process.stdout.clearLine(); 9 | process.stdout.cursorTo(0); 10 | process.stdout.write(Math.floor(percentage * 100) + "% " + log); 11 | })); 12 | 13 | compiler.run(function(err, stats) { 14 | if(err) 15 | return console.error(err.message); 16 | 17 | console.log(stats.toString({ 18 | colors: true 19 | })); 20 | }); 21 | -------------------------------------------------------------------------------- /bin/clean.js: -------------------------------------------------------------------------------- 1 | const del = require('del'); 2 | 3 | var items = ['dist/**', 'src/**/*.js', 'src/**/*.js.map', 'src/**/*.jsx', 'src/**/*.jsx.map']; 4 | 5 | items.forEach(function(toDelete, index, array) { 6 | del([toDelete]).then( 7 | function(paths) { 8 | if(paths.length > 0) 9 | console.log(toDelete + ' successfully removed'); 10 | else 11 | console.log('Error while deleting ' + toDelete + ' (empty?)'); 12 | } 13 | ) 14 | }); 15 | -------------------------------------------------------------------------------- /bin/server/hotReload.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var WebpackDevServer = require("webpack-dev-server"); 3 | var configClient = require("../../config/webpack.dev.client.js"); 4 | var configServer = require("../../config/webpack.dev.server.js"); 5 | 6 | var options = { 7 | chunk: false, 8 | chunkModules: false, 9 | modules: false, 10 | source: false, 11 | chunkOrigins: false 12 | }; 13 | 14 | new WebpackDevServer(webpack(configClient), { 15 | hot: true, 16 | historyApiFallback: true, 17 | stats: options 18 | }).listen(8081, "localhost", function(err) { 19 | if(err) 20 | console.log(err); 21 | 22 | console.log("Webpack Server launched with at localhost:8081 (Hot Module Replacement [HMR] enabled)"); 23 | }); 24 | 25 | webpack(configServer).watch({}, function(err, stats) { 26 | if(err) 27 | return console.error(err.message); 28 | 29 | console.log(stats.toString(options)); 30 | }); 31 | -------------------------------------------------------------------------------- /bin/server/index.js: -------------------------------------------------------------------------------- 1 | var express = require("express"); 2 | var compress = require("compression"); 3 | var path = require("path"); 4 | var serverSideRendering = require("../../dist/server/server.bundle.js"); 5 | 6 | var server = express(); 7 | const port = process.env.PORT || 8080; 8 | 9 | server.use(compress({ threshold: 0 })); 10 | server.use(express.static(path.resolve(__dirname, "..", "..", "dist", "client"))); 11 | server.use(function(req, res) { 12 | serverSideRendering.default(req, res); 13 | }); 14 | 15 | server.listen(port, function() { 16 | var host = this.address().address; 17 | console.log("Server launched at http://%s:%s", host, port); 18 | }); 19 | -------------------------------------------------------------------------------- /config/webpack.dev.client.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var shared = require("./webpack.shared.js"); 3 | 4 | var loaders = [{ 5 | test: /\.ts[x]?$/, 6 | loaders: [ 7 | "react-hot-loader", 8 | "ts-loader" 9 | ] 10 | }, { 11 | test: /\.css$/, 12 | loader: "style-loader!css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]" 13 | }, { 14 | test: /\.scss$/, 15 | loader: "style-loader!css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]!sass-loader" 16 | }, { 17 | test: /\.(jp[e]?g|png|gif|svg)$/i, 18 | loader: "file-loader?name=img/[name].[ext]" 19 | }, { 20 | test: /\.html$/, 21 | loader: "file-loader?name=[name].[ext]" 22 | }, { 23 | test: /\.ico$/, 24 | loader: "file-loader?name=[name].[ext]" 25 | }]; 26 | 27 | var client = { 28 | name: "dev.client", 29 | target: "web", 30 | entry: { 31 | "client.bundle": [ 32 | "webpack/hot/only-dev-server", 33 | "webpack-dev-server/client?http://localhost:8081", 34 | shared.APP_DIR + "/client" 35 | ] 36 | }, 37 | output: { 38 | filename: "[name].js", 39 | path: shared.CLIENT_BUILD_DIR, 40 | publicPath: "http://localhost:8081/" 41 | }, 42 | module: { 43 | loaders: loaders 44 | }, 45 | resolve: { 46 | extensions: ["", ".js", ".jsx", ".ts", ".tsx"] 47 | }, 48 | plugins: [ 49 | new webpack.HotModuleReplacementPlugin() 50 | ] 51 | }; 52 | 53 | module.exports = client; 54 | -------------------------------------------------------------------------------- /config/webpack.dev.server.js: -------------------------------------------------------------------------------- 1 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 2 | var shared = require("./webpack.shared.js"); 3 | 4 | var loaders = [{ 5 | test: /\.ts[x]?$/, 6 | loaders: [ 7 | "react-hot-loader", 8 | "ts-loader" 9 | ] 10 | }, { 11 | test: /\.css$/, 12 | loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]") 13 | }, { 14 | test: /\.scss$/, 15 | loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]!sass-loader") 16 | }, { 17 | test: /\.(jp[e]?g|png|gif|svg)$/i, 18 | loader: "file-loader?name=img/[name].[ext]" 19 | }, { 20 | test: /\.html$/, 21 | loader: "file-loader?name=[name].[ext]" 22 | }, { 23 | test: /\.ico$/, 24 | loader: "file-loader?name=[name].[ext]" 25 | }]; 26 | 27 | var server = { 28 | name: "dev.server", 29 | target: "node", 30 | externals: [ 31 | /^[a-z\-0-9]+$/, { 32 | "react-dom/server": true 33 | } 34 | ], 35 | entry: { 36 | "server.bundle": shared.APP_DIR + "/server" 37 | }, 38 | output: { 39 | filename: "[name].js", 40 | path: shared.SERVER_BUILD_DIR, 41 | publicPath: "http://localhost:8081/", 42 | libraryTarget: "commonjs2" 43 | }, 44 | module: { 45 | loaders: loaders 46 | }, 47 | resolve: { 48 | extensions: ["", ".js", ".jsx", ".ts", ".tsx"] 49 | }, 50 | plugins: [ 51 | new ExtractTextPlugin("[name].css") 52 | ] 53 | }; 54 | 55 | module.exports = server; 56 | -------------------------------------------------------------------------------- /config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | var webpack = require("webpack"); 2 | var ExtractTextPlugin = require("extract-text-webpack-plugin"); 3 | var shared = require("./webpack.shared.js"); 4 | 5 | var loaders = [{ 6 | test: /\.ts[x]?$/, 7 | loader: "ts-loader" 8 | }, { 9 | test: /\.css$/, 10 | loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]") 11 | }, { 12 | test: /\.scss$/, 13 | loader: ExtractTextPlugin.extract("style-loader", "css-loader?modules&localIdentName=[path]-[name]_[local]-[hash:base64:5]!sass-loader") 14 | }, { 15 | test: /\.(jp[e]?g|png|gif|svg)$/i, 16 | loader: "file-loader?name=img/[name].[ext]" 17 | }, { 18 | test: /\.html$/, 19 | loader: "file-loader?name=[name].[ext]" 20 | }, { 21 | test: /\.ico$/, 22 | loader: "file-loader?name=[name].[ext]" 23 | }]; 24 | 25 | var client = { 26 | name: "prod.client", 27 | target: "web", 28 | entry: { 29 | "client.bundle": shared.APP_DIR + "/client" 30 | }, 31 | output: { 32 | filename: "[name].js", 33 | path: shared.CLIENT_BUILD_DIR, 34 | publicPath: "/" 35 | }, 36 | module: { 37 | loaders: loaders 38 | }, 39 | resolve: { 40 | extensions: ["", ".js", ".jsx", ".ts", ".tsx"] 41 | }, 42 | plugins: [ 43 | new webpack.optimize.DedupePlugin(), 44 | new webpack.optimize.OccurrenceOrderPlugin(), 45 | new webpack.optimize.UglifyJsPlugin({ 46 | compress: { 47 | warnings: false 48 | } 49 | }), 50 | new webpack.DefinePlugin({ 51 | "process.env": { 52 | NODE_ENV: JSON.stringify("production") 53 | } 54 | }), 55 | 56 | new ExtractTextPlugin("[name].css") 57 | ] 58 | }; 59 | 60 | var server = { 61 | name: "prod.server", 62 | target: "node", 63 | externals: [ 64 | /^[a-z\-0-9]+$/, { 65 | "react-dom/server": true 66 | } 67 | ], 68 | entry: { 69 | "server.bundle": shared.APP_DIR + "/server" 70 | }, 71 | output: { 72 | filename: "[name].js", 73 | path: shared.SERVER_BUILD_DIR, 74 | publicPath: "/", 75 | libraryTarget: "commonjs2" 76 | }, 77 | module: { 78 | loaders: loaders 79 | }, 80 | resolve: { 81 | extensions: ["", ".js", ".jsx", ".ts", ".tsx"] 82 | }, 83 | plugins: [ 84 | new webpack.optimize.DedupePlugin(), 85 | new webpack.optimize.OccurrenceOrderPlugin(), 86 | new webpack.optimize.UglifyJsPlugin({ 87 | compress: { 88 | warnings: false 89 | } 90 | }), 91 | new webpack.DefinePlugin({ 92 | "process.env": { 93 | NODE_ENV: JSON.stringify("production") 94 | } 95 | }), 96 | 97 | new ExtractTextPlugin("[name].css") 98 | ] 99 | }; 100 | 101 | module.exports = [client, server]; 102 | -------------------------------------------------------------------------------- /config/webpack.shared.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | exports.CLIENT_BUILD_DIR = path.resolve(__dirname, "..", "dist", "client"); 4 | exports.SERVER_BUILD_DIR = path.resolve(__dirname, "..", "dist", "server"); 5 | exports.APP_DIR = path.resolve(__dirname, "..", "src"); 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactjs-typescript-isomorphic-starterkit", 3 | "version": "2.0.0", 4 | "description": "A React.js typescript isomorphic template with Webpack and react-router", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "clean": "node ./bin/clean.js", 8 | "postinstall": "typings install && npm run deploy", 9 | "server": "node ./bin/server", 10 | "build": "npm run clean && node ./bin/bundler/prod.js", 11 | "deploy": "npm run build && npm run server", 12 | "watch": "npm run clean && node ./bin/bundler/dev.js && concurrent \"node ./bin/server/hotReload.js\" \"nodemon ./bin/server --watch dist -e js\" --kill-others" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/ayoubdev/reactjs-typescript-isomorphic-starterkit.git" 17 | }, 18 | "bugs": { 19 | "url": "https://github.com/ayoubdev/reactjs-typescript-isomorphic-starterkit/issues" 20 | }, 21 | "keywords": [ 22 | "reactjs", 23 | "webpack", 24 | "react-router", 25 | "boilerplate", 26 | "template", 27 | "typescript", 28 | "transpilation", 29 | "isomorphic", 30 | "server side rendering", 31 | "client side rendering", 32 | "starter", 33 | "kit", 34 | "starterkit", 35 | "starter-kit" 36 | ], 37 | "author": "Ayoub ADIB ", 38 | "license": "MIT", 39 | "devDependencies": { 40 | "concurrently": "^2.1.0", 41 | "css-loader": "^0.23.1", 42 | "del": "^2.2.1", 43 | "extract-text-webpack-plugin": "^1.0.1", 44 | "file-loader": "^0.9.0", 45 | "fs": "0.0.2", 46 | "node-sass": "^3.8.0", 47 | "nodemon": "^1.9.2", 48 | "react-hot-loader": "^1.3.0", 49 | "sass-loader": "^3.2.1", 50 | "style-loader": "^0.13.1", 51 | "ts-loader": "^0.8.2", 52 | "typescript": "^1.8.10", 53 | "typings": "^1.3.0", 54 | "webpack": "^1.13.1", 55 | "webpack-dev-server": "^1.14.1" 56 | }, 57 | "dependencies": { 58 | "compression": "^1.6.2", 59 | "express": "^4.14.0", 60 | "react": "^15.1.0", 61 | "react-dom": "^15.1.0", 62 | "react-router": "^2.4.1" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/client/index.tsx: -------------------------------------------------------------------------------- 1 | import * as ReactDOM from "react-dom"; 2 | import routes from "../shared/routes"; 3 | import "../shared/favicon.ico"; 4 | 5 | ReactDOM.render(routes, document.getElementById("app")); 6 | -------------------------------------------------------------------------------- /src/server/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { renderToString } from "react-dom/server"; 3 | import { match, RouterContext } from "react-router"; 4 | import routes from "../shared/routes"; 5 | import "../shared/favicon.ico"; 6 | 7 | function renderHTML(componentHTML: any) { 8 | if(process.env.NODE_ENV === "production") 9 | return ` 10 | 11 | 12 | 13 | 14 | React Isomorphic Starter Kit 15 | 16 | 17 | 18 | 19 |
${componentHTML}
20 | 21 | 22 | 23 | 24 | `; 25 | else 26 | return ` 27 | 28 | 29 | 30 | 31 | React Isomorphic Starter Kit 32 | 33 | 34 | 35 |
${componentHTML}
36 | 37 | 38 | 39 | 40 | `; 41 | } 42 | 43 | export default function(req: any, res: any) { 44 | console.log(req.url); 45 | match({ routes, location: req.url }, (error: any, redirectLocation: any, renderProps: any) => { 46 | if(error) { 47 | res.status(500).send(error.message); 48 | } else if(redirectLocation) { 49 | res.redirect(302, redirectLocation.pathname + redirectLocation.search); 50 | } else if(renderProps) { 51 | res.status(200).send(renderHTML(renderToString())); 52 | } else { 53 | res.status(404).send("Not found"); 54 | } 55 | }); 56 | } 57 | -------------------------------------------------------------------------------- /src/shared/components/404/404.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | class NotFoundComponent extends React.Component { 4 | constructor(props:any) { 5 | super(props); 6 | } 7 | 8 | render() { 9 | return ( 10 |
11 |

12 | Oups, route not found :( [404] 13 |

14 |
15 | ); 16 | } 17 | } 18 | 19 | export default NotFoundComponent; -------------------------------------------------------------------------------- /src/shared/components/app.scss: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | -------------------------------------------------------------------------------- /src/shared/components/app.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Link } from "react-router"; 3 | import Header from "./header/header"; 4 | import Footer from "./footer/footer"; 5 | import "./app.scss"; 6 | 7 | let styles = { 8 | link: { 9 | display: "block", 10 | position: "absolute", 11 | top: "35vh", 12 | left: "1.5em", 13 | color: "black", 14 | backgroundColor: "lightgrey", 15 | fontSize: "1.5em", 16 | textDecoration: "none", 17 | border: "1px solid black" 18 | }, 19 | footer: { 20 | color: "white", 21 | fontSize: "2vmin", 22 | fontWeight: "bold", 23 | textAlign: "center" 24 | } 25 | }; 26 | 27 | interface AppPropTypes { 28 | children: React.ReactChild 29 | } 30 | 31 | class App extends React.Component { 32 | render() { 33 | return( 34 |
35 |
36 | Isomorphic React Starter Kit v2.0 37 |
38 | 39 | {this.props.children} 40 | Go back 41 | 42 | 50 |
51 | ); 52 | } 53 | } 54 | 55 | export default App; 56 | -------------------------------------------------------------------------------- /src/shared/components/example/example.css: -------------------------------------------------------------------------------- 1 | .text { 2 | color: red; 3 | } 4 | 5 | .logo { 6 | max-width: 40vw; 7 | height: auto; 8 | } 9 | -------------------------------------------------------------------------------- /src/shared/components/example/example.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | const styles = require("./example.css"); 3 | 4 | class Example extends React.Component { 5 | constructor(props: any) { 6 | super(props); 7 | } 8 | 9 | componentDidMount() { 10 | console.log("Client side: componentDidMount()"); 11 | } 12 | 13 | onClick() { 14 | console.log("Client side: onClick()"); 15 | } 16 | 17 | render() { 18 | return( 19 |
20 |

Example Component:

21 | 22 | 23 | 24 |
25 | ); 26 | } 27 | } 28 | 29 | export default Example; 30 | -------------------------------------------------------------------------------- /src/shared/components/example/img/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adbayb/reactjs-typescript-isomorphic-starterkit/92fb787a677bd1f1e513532bd2f9e2915bf3f9eb/src/shared/components/example/img/react.png -------------------------------------------------------------------------------- /src/shared/components/footer/footer.scss: -------------------------------------------------------------------------------- 1 | .footer { 2 | position: absolute; 3 | bottom: 0; 4 | height: 20vh; 5 | width: 100%; 6 | background-color: black; 7 | } 8 | -------------------------------------------------------------------------------- /src/shared/components/footer/footer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | const styles: any = require("./footer.scss"); 3 | 4 | interface Props { 5 | children?: React.ReactNode 6 | } 7 | 8 | const Footer: React.StatelessComponent = (props: Props) => { 9 | return( 10 |
11 | {props.children} 12 |
13 | ); 14 | }; 15 | 16 | export default Footer; 17 | -------------------------------------------------------------------------------- /src/shared/components/header/header.scss: -------------------------------------------------------------------------------- 1 | .header { 2 | width: 100%; 3 | height: 10vh; 4 | background-color: black; 5 | margin: 0; 6 | padding: 0; 7 | &> p { 8 | font-size: 4vmin; 9 | margin: 0; 10 | padding: 0; 11 | } 12 | } 13 | 14 | .text { 15 | font-size: 3vmin; 16 | font-weight: bold; 17 | text-align: center; 18 | color: yellowgreen; 19 | } 20 | -------------------------------------------------------------------------------- /src/shared/components/header/header.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | const styles: any = require("./header.scss"); 3 | 4 | interface Props { 5 | //Typescript ne gère pour le moment pas les children (v1.8.10). On doit mettre any pour éviter les erreurs du type: 6 | //Property 'children' is missing in type 'IntrinsicAttributes & IntrinsicClassAttributes 7 | //cf. https://github.com/Microsoft/TypeScript/issues/8588 && https://github.com/Microsoft/TypeScript/issues/6471 8 | children?: String 9 | } 10 | 11 | const Header: React.StatelessComponent = (props: Props) => { 12 | return( 13 |
14 |

15 | {props.children} 16 |

17 |
18 | ); 19 | }; 20 | 21 | export default Header; 22 | -------------------------------------------------------------------------------- /src/shared/components/navbar/navbar.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { Link } from "react-router"; 3 | 4 | class Navbar extends React.Component { 5 | render() { 6 | return( 7 | 13 | ); 14 | } 15 | } 16 | 17 | export default Navbar; 18 | -------------------------------------------------------------------------------- /src/shared/components/single/single.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface Props { 4 | children: React.ReactChild 5 | } 6 | 7 | const Single = (props: Props) => { 8 | return( 9 |
10 | {props.children} 11 |
12 | ); 13 | }; 14 | 15 | export default Single; 16 | -------------------------------------------------------------------------------- /src/shared/components/welcome/welcome.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | 3 | interface Props { 4 | params: { 5 | name: String, 6 | age: Number 7 | } 8 | } 9 | 10 | class Welcome extends React.Component { 11 | constructor(props: Props) { 12 | super(props); 13 | } 14 | 15 | render() { 16 | let params = this.props.params; 17 | 18 | return( 19 |

Welcome {params.name} to React world ! [You are {params.age} years old]

20 | ); 21 | } 22 | } 23 | 24 | export default Welcome; 25 | -------------------------------------------------------------------------------- /src/shared/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adbayb/reactjs-typescript-isomorphic-starterkit/92fb787a677bd1f1e513532bd2f9e2915bf3f9eb/src/shared/favicon.ico -------------------------------------------------------------------------------- /src/shared/routes.tsx: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | import { browserHistory, Router, Route, IndexRoute } from "react-router"; 3 | import App from "./components/app"; 4 | import Example from "./components/example/example"; 5 | import Welcome from "./components/welcome/welcome"; 6 | import Navbar from "./components/navbar/navbar"; 7 | import Single from "./components/single/single"; 8 | import NotFound from "./components/404/404"; 9 | 10 | export default( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ); 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES5", 5 | "allowJs": true, 6 | "jsx": "react", 7 | "noImplicitAny": true, 8 | "noImplicitReturns": true, 9 | "preserveConstEnums": true, 10 | "experimentalDecorators": true, 11 | "removeComments": true, 12 | "sourceMap": true 13 | }, 14 | "files": [ 15 | "./typings/index.d.ts", 16 | "./src/server/index.tsx", 17 | "./src/client/index.tsx" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "reactjs-typescript-isomorphic-starterkit", 3 | "globalDependencies": { 4 | "node": "registry:env/node#6.0.0+20160610031852", 5 | "react": "registry:dt/react#0.14.0+20160602151522", 6 | "react-dom": "registry:dt/react-dom#0.14.0+20160412154040", 7 | "react-router": "registry:dt/react-router#2.0.0+20160620164637", 8 | "react-router/history": "registry:dt/react-router/history#2.0.0+20160608102730" 9 | } 10 | } 11 | --------------------------------------------------------------------------------