├── .prettierrc
├── src
├── js
│ ├── main.js
│ ├── components
│ │ └── Example.js
│ └── App.js
├── css
│ ├── global.css
│ └── reset.css
└── index.html
├── .babelrc
├── .eslintrc
├── static-assets.js
├── webpack.config.js
├── LICENCE
├── .gitignore
├── package.json
└── README.md
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | quoteProps: "consistent",
3 | printWidth: 110,
4 | tabWidth: 2,
5 | singleQuote: true,
6 | bracketSpacing: false
7 | }
8 |
--------------------------------------------------------------------------------
/src/js/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {render} from 'react-dom';
3 | import App from './App.js';
4 |
5 | render(, document.querySelector('[data-app="main"]'));
6 |
--------------------------------------------------------------------------------
/src/css/global.css:
--------------------------------------------------------------------------------
1 | @import url('./reset.css');
2 |
3 | body {
4 | padding: 2rem;
5 | background: #efefef;
6 | color: #252525;
7 | font-family: sans-serif;
8 | }
9 |
10 | a:not([class]) {
11 | color: currentColor;
12 | }
13 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "modules": false,
7 | "targets": {
8 | "esmodules": true
9 | }
10 | }
11 | ],
12 | "@babel/preset-react"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["prettier", "plugin:react/recommended"],
3 | "env": {
4 | "browser": true,
5 | "es6": true
6 | },
7 | "parserOptions": {
8 | "parser": "babel-eslint",
9 | "sourceType": "module",
10 | "ecmaVersion": 2017
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/js/components/Example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const Example = ({text, label}) => (
5 |
8 | );
9 |
10 | Example.propTypes = {
11 | text: PropTypes.string,
12 | label: PropTypes.string
13 | };
14 |
15 | export default Example;
16 |
--------------------------------------------------------------------------------
/src/js/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Example from './components/Example.js';
4 |
5 | const App = () => (
6 |
7 | Hello, I’m your app, using the minimal React app base.
8 |
9 | Head over to the repo to find out more info.
10 |
11 |
12 |
13 | );
14 |
15 | export default App;
16 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Minimal React Base, pal
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/static-assets.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const postcss = require('postcss');
3 | const atImport = require('postcss-import');
4 | const cssnano = require('cssnano');
5 | const isProduction = process.env.NODE_ENV === 'production';
6 |
7 | const paths = {
8 | css: {
9 | in: './src/css/global.css',
10 | out: './dist/css/global.css'
11 | },
12 | html: {
13 | in: './src/index.html',
14 | out: './dist/index.html'
15 | }
16 | };
17 |
18 | const runner = async () => {
19 | const cssSrc = fs.readFileSync(paths.css.in, 'utf8');
20 | const htmlSrc = fs.readFileSync(paths.html.in, 'utf8');
21 |
22 | const {css} = await postcss()
23 | .use(atImport())
24 | .use(cssnano({sourcemap: !isProduction}))
25 | .process(cssSrc, {
26 | from: paths.css.in
27 | });
28 |
29 | fs.writeFileSync(paths.css.out, css);
30 | fs.writeFileSync(paths.html.out, htmlSrc);
31 |
32 | return true;
33 | };
34 |
35 | runner();
36 | module.exports = runner;
37 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const TerserPlugin = require('terser-webpack-plugin');
2 |
3 | const paths = {
4 | in: `${__dirname}/src/js/main.js`,
5 | out: {path: `${__dirname}/dist/js/`, name: 'main.js'}
6 | };
7 |
8 | const isProd = process.env.NODE_ENV === 'production';
9 |
10 | module.exports = {
11 | entry: paths.in,
12 | mode: isProd ? 'production' : 'development',
13 | module: {
14 | rules: [
15 | {
16 | test: /\.(js)$/,
17 | exclude: /node_modules/,
18 | use: ['babel-loader']
19 | }
20 | ]
21 | },
22 | output: {
23 | path: paths.out.path,
24 | filename: paths.out.name
25 | },
26 | optimization: {
27 | minimizer: [
28 | new TerserPlugin({
29 | sourceMap: !isProd
30 | })
31 | ]
32 | },
33 | resolve: {
34 | alias: {
35 | 'react': 'preact/compat',
36 | 'react$': 'preact/compat',
37 | 'react-dom': 'preact/compat',
38 | 'react-dom$': 'preact/compat'
39 | }
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
1 | MIT License
2 | -----------
3 |
4 | Copyright (c) 2020 Andy Bell (https://hankchizljaw.com)
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | # next.js build output
61 | .next
62 |
63 | # postgres data files
64 | pgdata
65 |
66 | # Vim swap files
67 | .swp
68 |
69 | # Mac slime
70 | .DS_Store
71 |
72 | # Dist
73 | dist
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "minimal-react-base",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "prelaunch": "rm -r -f dist && mkdir -p dist/css",
8 | "static": "node static-assets.js",
9 | "start": "npm run prelaunch && concurrently 'webpack --watch' 'watch \"npm run static\" src --ignoreDirectoryPattern /src/js/' 'npx serve ./dist'",
10 | "build": "npm run prelaunch && NODE_ENV=production concurrently 'webpack' 'npm run static'"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/hankchizljaw/minimal-react-base.git"
15 | },
16 | "keywords": [],
17 | "author": "",
18 | "license": "MIT",
19 | "bugs": {
20 | "url": "https://github.com/hankchizljaw/minimal-react-base/issues"
21 | },
22 | "homepage": "https://github.com/hankchizljaw/minimal-react-base#readme",
23 | "devDependencies": {
24 | "@babel/core": "^7.7.7",
25 | "@babel/preset-env": "^7.7.7",
26 | "@babel/preset-react": "^7.7.4",
27 | "babel-eslint": "^10.0.3",
28 | "babel-loader": "^8.0.6",
29 | "concurrently": "^5.0.2",
30 | "cssnano": "^4.1.10",
31 | "eslint": "^6.8.0",
32 | "eslint-config-prettier": "^6.9.0",
33 | "eslint-plugin-react": "^7.17.0",
34 | "postcss": "^7.0.26",
35 | "postcss-import": "^12.0.1",
36 | "terser-webpack-plugin": "^2.3.1",
37 | "watch": "^1.0.2",
38 | "webpack": "^4.41.5",
39 | "webpack-cli": "^3.3.10"
40 | },
41 | "dependencies": {
42 | "preact": "^10.1.1",
43 | "preact-compat": "^3.19.0",
44 | "prop-types": "^15.7.2",
45 | "react": "^16.12.0",
46 | "react-dom": "^16.12.0"
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/css/reset.css:
--------------------------------------------------------------------------------
1 | /*
2 | A modern CSS reset: https://hankchizljaw.com/wrote/a-modern-css-reset/
3 | */
4 |
5 | /* Box sizing rules */
6 | *,
7 | *::before,
8 | *::after {
9 | box-sizing: border-box;
10 | }
11 |
12 | /* Remove default padding */
13 | ul[class],
14 | ol[class] {
15 | padding: 0;
16 | }
17 |
18 | /* Remove default margin */
19 | body,
20 | h1,
21 | h2,
22 | h3,
23 | h4,
24 | p,
25 | ul[class],
26 | ol[class],
27 | li,
28 | figure,
29 | figcaption,
30 | blockquote,
31 | dl,
32 | dd {
33 | margin: 0;
34 | }
35 |
36 | /* Set core body defaults */
37 | body {
38 | min-height: 100vh;
39 | scroll-behavior: smooth;
40 | text-rendering: optimizeSpeed;
41 | line-height: 1.5;
42 | }
43 |
44 | /* Remove list styles on ul, ol elements with a class attribute */
45 | ul[class],
46 | ol[class] {
47 | list-style: none;
48 | }
49 |
50 | /* A elements that don't have a class get default styles */
51 | a:not([class]) {
52 | text-decoration-skip-ink: auto;
53 | }
54 |
55 | /* Make images easier to work with */
56 | img {
57 | max-width: 100%;
58 | display: block;
59 | }
60 |
61 | /* Natural flow and rhythm in articles by default */
62 | article > * + * {
63 | margin-top: 1em;
64 | }
65 |
66 | /* Inherit fonts for inputs and buttons */
67 | input,
68 | button,
69 | textarea,
70 | select {
71 | font: inherit;
72 | }
73 |
74 | /* Remove all animations and transitions for people that prefer not to see them */
75 | @media (prefers-reduced-motion: reduce) {
76 | * {
77 | animation-duration: 0.01ms !important;
78 | animation-iteration-count: 1 !important;
79 | transition-duration: 0.01ms !important;
80 | scroll-behavior: auto !important;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Minimal React Base
2 |
3 | This is a little starting point for if you want to sling some React on a HTML page with some CSS.
4 |
5 | The secret though—*[lowers voice]*—is that it actually spits out Preact code instead. Because of that, by default, it’s a ~19kb vs ~131kb (non-gzipped) build.
6 |
7 | [See a live demo](https://minimal-react-base.netlify.com/)
8 |
9 | ## Features
10 |
11 | - Webpack setup for bundling your JavaScript
12 | - Static processor which looks after your HTML and CSS
13 | - PostCSS with `@import` support and a [modern CSS reset](https://github.com/hankchizljaw/modern-css-reset)
14 |
15 | ## Getting started
16 |
17 | 1) First up, clone this repo or grab a zip.
18 | 2) Open up the project and run `npm install`
19 | 3) To run it in dev mode, run `npm start`
20 | 4) To create a production build, run `npm build`
21 |
22 | ## Contributing
23 |
24 | Contribution is more than welcome—especially from those in the community that specialise in React/Preact.
25 |
26 | Please don’t open a PR without first opening an issue to discuss your proposals. Opinionated code changes probably won't get through, but improvements to the project are more than welcome.
27 |
28 | ## Code of Conduct
29 |
30 | ### Our Pledge
31 |
32 | In the interest of fostering an open and welcoming environment, we as
33 | contributors and maintainers pledge to making participation in our project and
34 | our community a harassment-free experience for everyone, regardless of age, body
35 | size, disability, ethnicity, gender identity and expression, level of experience,
36 | nationality, personal appearance, race, religion, or sexual identity and
37 | orientation.
38 |
39 | ### Our Standards
40 |
41 | Examples of behavior that contributes to creating a positive environment
42 | include:
43 |
44 | - Using welcoming and inclusive language
45 | - Being respectful of differing viewpoints and experiences
46 | - Gracefully accepting constructive criticism
47 | - Focusing on what is best for the community
48 | - Showing empathy towards other community members
49 |
50 | Examples of unacceptable behavior by participants include:
51 |
52 | - The use of sexualized language or imagery and unwelcome sexual attention or
53 | advances
54 | - Trolling, insulting/derogatory comments, and personal or political attacks
55 | - Public or private harassment
56 | - Publishing others' private information, such as a physical or electronic
57 | address, without explicit permission
58 | - Other conduct which could reasonably be considered inappropriate in a
59 | professional setting
60 |
61 | ### Our Responsibilities
62 |
63 | Project maintainers are responsible for clarifying the standards of acceptable
64 | behavior and are expected to take appropriate and fair corrective action in
65 | response to any instances of unacceptable behavior.
66 |
67 | Project maintainers have the right and responsibility to remove, edit, or
68 | reject comments, commits, code, wiki edits, issues, and other contributions
69 | that are not aligned to this Code of Conduct, or to ban temporarily or
70 | permanently any contributor for other behaviors that they deem inappropriate,
71 | threatening, offensive, or harmful.
72 |
73 | ### Scope
74 |
75 | This Code of Conduct applies both within project spaces and in public spaces
76 | when an individual is representing the project or its community. Examples of
77 | representing a project or community include using an official project e-mail
78 | address, posting via an official social media account, or acting as an appointed
79 | representative at an online or offline event. Representation of a project may be
80 | further defined and clarified by project maintainers.
81 |
82 | ### Enforcement
83 |
84 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
85 | reported by contacting the project team at me@andy-bell.design. All
86 | complaints will be reviewed and investigated and will result in a response that
87 | is deemed necessary and appropriate to the circumstances. The project team is
88 | obligated to maintain confidentiality with regard to the reporter of an incident.
89 | Further details of specific enforcement policies may be posted separately.
90 |
91 | Project maintainers who do not follow or enforce the Code of Conduct in good
92 | faith may face temporary or permanent repercussions as determined by other
93 | members of the project's leadership.
94 |
95 | ### Attribution
96 |
97 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
98 | available at [http://contributor-covenant.org/version/1/4][version]
99 |
100 | [homepage]: http://contributor-covenant.org
101 | [version]: http://contributor-covenant.org/version/1/4/
102 |
103 |
--------------------------------------------------------------------------------