├── .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 |
--------------------------------------------------------------------------------