├── .babelrc ├── .eslintrc.js ├── .gitignore ├── .prettierrc.js ├── LICENSE ├── README.md ├── config └── webpack │ ├── webpack.common.ts │ ├── webpack.dev.ts │ ├── webpack.prod.ts │ └── webpack.test.ts ├── deno-react-love.png ├── package-lock.json ├── package.json ├── scripts └── open-browser.js ├── server └── staticServer.ts ├── src ├── App.tsx ├── index.html ├── index.tsx └── styles.css └── tsconfig.json /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/env", 4 | "@babel/react", 5 | "@babel/typescript" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', 3 | plugins: ['@typescript-eslint'], 4 | extends: [ 5 | 'plugin:@typescript-eslint/recommended', 6 | 'plugin:prettier/recommended', 7 | 'prettier/@typescript-eslint', 8 | ], 9 | parserOptions: { 10 | project: './tsconfig.json', 11 | ecmaVersion: 2018, 12 | sourceType: 'module', 13 | }, 14 | rules: { 15 | "@typescript-eslint/no-unused-vars": "off" 16 | }, 17 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | server/static/* 4 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | trailingComma: 'all', 4 | singleQuote: true, 5 | printWidth: 120, 6 | tabWidth: 2, 7 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 dudiharush 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-deno-app-starter 2 | A starter template for React, Babel, Webpack And Typescript, with Deno on the server. 3 | 4 | # installation steps 5 | 6 | 1. install Deno: https://github.com/denoland/deno_install 7 | 2. open your code editor/commandline with admin priviledges. 8 | 3. run: git clone https://github.com/dudiharush/react-deno-app-starter.git 9 | 4. cd into the project directory. 10 | 5. run: npm i 11 | 6. run: npm start 12 | 13 | -------------------------------------------------------------------------------- /config/webpack/webpack.common.ts: -------------------------------------------------------------------------------- 1 | import { join, resolve } from 'path' 2 | import webpack from 'webpack' 3 | import HtmlWebpackPlugin from 'html-webpack-plugin' 4 | import { CleanWebpackPlugin } from 'clean-webpack-plugin' 5 | 6 | export interface WebpackEnv { 7 | mode?: string 8 | debug?: boolean 9 | } 10 | 11 | export const getCommonConfig = (env: WebpackEnv = {}): webpack.Configuration => { 12 | const { mode = 'development', debug = true } = env 13 | 14 | return { 15 | mode: 'none', 16 | entry: { 17 | index: join(resolve('src'), 'index.tsx'), 18 | }, 19 | output: { 20 | pathinfo: debug === true, 21 | path: resolve('dist'), 22 | filename: '[name].js', 23 | }, 24 | resolve: { 25 | extensions: ['.js', '.jsx', '.ts', '.tsx'], 26 | }, 27 | module: { 28 | rules: [ 29 | { 30 | test: /\.tsx?$/, 31 | exclude: /node_modules/, 32 | use: 'babel-loader', 33 | }, 34 | ], 35 | }, 36 | plugins: [ 37 | new CleanWebpackPlugin(), 38 | new HtmlWebpackPlugin({ 39 | title: 'Deno + React = ❤️', 40 | template: 'src/index.html', 41 | }), 42 | ], 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/webpack/webpack.dev.ts: -------------------------------------------------------------------------------- 1 | import merge from 'webpack-merge' 2 | import { getCommonConfig } from './webpack.common' 3 | import { Configuration as WebpackConfiguration } from 'webpack' 4 | 5 | export const getDevConfig = (openBrowser = true): WebpackConfiguration => ({ 6 | mode: 'development', 7 | devtool: 'inline-source-map', 8 | module: { 9 | rules: [ 10 | { 11 | test: /\.css$/, 12 | exclude: /node_modules/, 13 | use: ['style-loader', 'css-loader'], 14 | }, 15 | ], 16 | }, 17 | }) 18 | 19 | export default merge(getCommonConfig(), getDevConfig()) 20 | -------------------------------------------------------------------------------- /config/webpack/webpack.prod.ts: -------------------------------------------------------------------------------- 1 | import merge from 'webpack-merge' 2 | import { getCommonConfig } from './webpack.common' 3 | import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin' 4 | import TerserJSPlugin from 'terser-webpack-plugin' 5 | import MiniCssExtractPlugin from 'mini-css-extract-plugin' 6 | import webpack from 'webpack' 7 | 8 | const prodConfig: webpack.Configuration = { 9 | mode: 'production', 10 | optimization: { 11 | minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], 12 | }, 13 | module: { 14 | rules: [ 15 | { 16 | test: /\.css$/, 17 | exclude: /node_modules/, 18 | use: [ 19 | { 20 | loader: MiniCssExtractPlugin.loader, 21 | }, 22 | 'css-loader', 23 | ], 24 | }, 25 | ], 26 | }, 27 | plugins: [ 28 | new MiniCssExtractPlugin({ 29 | filename: '[name].css', 30 | chunkFilename: '[id].css', 31 | ignoreOrder: false, 32 | }), 33 | ], 34 | } 35 | 36 | export default merge(getCommonConfig(), prodConfig) 37 | -------------------------------------------------------------------------------- /config/webpack/webpack.test.ts: -------------------------------------------------------------------------------- 1 | import { getDevConfig } from './webpack.dev' 2 | import { getCommonConfig } from './webpack.common' 3 | import merge from 'webpack-merge' 4 | 5 | export default merge(getCommonConfig(), getDevConfig(false)) 6 | -------------------------------------------------------------------------------- /deno-react-love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dudiharush/react-deno-app-starter/976a3c624d1fa3f79ebe57b8051e50f43585491f/deno-react-love.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-deno-app-starter", 3 | "version": "1.0.0", 4 | "description": "A starter template for React, Babel, Webpack And Typescript, with Deno on the server", 5 | "repository": "https://github.com/dudiharush/react-deno-app-starter.git", 6 | "author": "David Harush ", 7 | "license": "MIT", 8 | "scripts": { 9 | "check-types": "tsc", 10 | "build:prod": "webpack -p --config=config/webpack/webpack.prod.ts", 11 | "build:dev": "webpack -p --config=config/webpack/webpack.dev.ts", 12 | "copy-files": "copyfiles -f dist/*.* server/static", 13 | "clean-build-copy:prod": "run-s -s clean-dist build:prod copy-files", 14 | "clean-build-copy:dev": "run-s -s clean-dist build:dev copy-files", 15 | "build": "npm run clean-build-copy:prod", 16 | "clean-dist": "rimraf dist/* server/static/*", 17 | "start": "run-s clean-build-copy:dev run-and-open", 18 | "run-and-open": "run-p run-server open-browser", 19 | "run-server": "deno run --allow-read --allow-net server/staticServer.ts", 20 | "open-browser": "node scripts/open-browser.js", 21 | "lint:fix": "eslint src/ --ext .tsx,.ts,.js --fix", 22 | "typecheck": "tsc" 23 | }, 24 | "dependencies": { 25 | "react": "^16.11.0", 26 | "react-dom": "^16.11.0", 27 | "rimraf": "^3.0.0", 28 | "npm-run-all": "^4.1.5" 29 | }, 30 | "devDependencies": { 31 | "@babel/core": "^7.6.4", 32 | "@babel/preset-env": "^7.6.3", 33 | "@babel/preset-react": "^7.6.3", 34 | "@babel/preset-typescript": "^7.6.0", 35 | "@types/html-webpack-plugin": "^3.2.1", 36 | "@types/mini-css-extract-plugin": "^0.8.0", 37 | "@types/node": "^12.12.6", 38 | "@types/optimize-css-assets-webpack-plugin": "^5.0.1", 39 | "@types/react": "^16.9.9", 40 | "@types/react-dom": "^16.9.2", 41 | "@types/terser-webpack-plugin": "^2.2.0", 42 | "@types/webpack": "^4.39.8", 43 | "@types/webpack-merge": "^4.1.5", 44 | "@typescript-eslint/eslint-plugin": "^2.34.0", 45 | "@typescript-eslint/parser": "^3.0.0", 46 | "babel-loader": "^8.0.6", 47 | "clean-webpack-plugin": "^3.0.0", 48 | "copyfiles": "^2.2.0", 49 | "cross-env": "^6.0.3", 50 | "css-loader": "^3.2.0", 51 | "eslint": "^7.1.0", 52 | "eslint-config-prettier": "^6.5.0", 53 | "eslint-plugin-prettier": "^3.1.1", 54 | "html-webpack-plugin": "^3.2.0", 55 | "husky": "^3.0.9", 56 | "lint-staged": "^9.4.2", 57 | "mini-css-extract-plugin": "^0.8.0", 58 | "open": "^7.0.2", 59 | "openurl": "^1.1.1", 60 | "opn": "^6.0.0", 61 | "optimize-css-assets-webpack-plugin": "^5.0.3", 62 | "prettier": "^1.18.2", 63 | "react-docgen-typescript-loader": "^3.3.0", 64 | "style-loader": "^1.0.0", 65 | "terser-webpack-plugin": "^2.2.1", 66 | "ts-node": "^8.4.1", 67 | "typescript": "^3.6.4", 68 | "webpack": "^4.41.2", 69 | "webpack-cli": "^3.3.9", 70 | "webpack-dev-server": "^3.9.0", 71 | "webpack-merge": "^4.2.2" 72 | }, 73 | "lint-staged": { 74 | "*.{ts,tsx}": [ 75 | "yarn run lint:fix", 76 | "git add" 77 | ] 78 | }, 79 | "husky": { 80 | "hooks": { 81 | "pre-commit": "lint-staged" 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /scripts/open-browser.js: -------------------------------------------------------------------------------- 1 | const open = require('open'); 2 | 3 | (async () => { 4 | await open('http://localhost:8000'); 5 | })() 6 | 7 | console.log('opening browser...') -------------------------------------------------------------------------------- /server/staticServer.ts: -------------------------------------------------------------------------------- 1 | import { Application, send } from 'https://deno.land/x/oak/mod.ts' 2 | import * as path from 'https://deno.land/std/path/mod.ts' 3 | ;(async () => { 4 | const app = new Application() 5 | 6 | app.use(async ctx => { 7 | const filePath = path.join(Deno.cwd(), 'server', 'static') 8 | await send(ctx, ctx.request.url.pathname, { 9 | root: filePath, 10 | index: 'index.html', 11 | }) 12 | }) 13 | 14 | console.log('server is runing on: http://localhost:8000') 15 | await app.listen({ port: 8000 }) 16 | })() 17 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function App(): JSX.Element { 4 | return

Deno + React = ❤️

5 | } 6 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import App from './App' 4 | import './styles.css' 5 | 6 | ReactDOM.render(, document.getElementById('app')) 7 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | #app p { 2 | font-family: sans-serif; 3 | text-align: center; 4 | font-size: 40px; 5 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "moduleResolution": "node", 5 | "noEmit": true, 6 | "skipLibCheck": true, 7 | "isolatedModules": true, 8 | "target": "es5", 9 | "module": "commonjs", 10 | "allowJs": false, 11 | "allowUmdGlobalAccess": false, 12 | "allowUnreachableCode": false, 13 | "allowUnusedLabels": false, 14 | "alwaysStrict": true, 15 | "checkJs": false, 16 | "esModuleInterop": true, 17 | "disableSizeLimit": false, 18 | "jsx": "react", 19 | "jsxFactory": "React.createElement", 20 | "lib": ["DOM"], 21 | "noFallthroughCasesInSwitch": false, 22 | "noImplicitAny": true, 23 | "noImplicitReturns": true, 24 | "noImplicitThis": true, 25 | "noImplicitUseStrict": false, 26 | "noStrictGenericChecks": false, 27 | "noUnusedLocals": false, 28 | "noUnusedParameters": false, 29 | "preserveConstEnums": false, 30 | "removeComments": false, 31 | "resolveJsonModule": true, 32 | "strict": true, 33 | "strictBindCallApply": true, 34 | "strictFunctionTypes": true, 35 | "strictNullChecks": true, 36 | "strictPropertyInitialization": true, 37 | "suppressExcessPropertyErrors": false, 38 | "suppressImplicitAnyIndexErrors": false 39 | }, 40 | "include": ["src", "config"] 41 | } 42 | --------------------------------------------------------------------------------