├── .gitignore ├── .babelrc ├── .editorconfig ├── src ├── index.js └── components │ ├── home.js │ ├── app.js │ ├── profile.js │ └── header.js ├── README.md ├── webpack.config.babel.js ├── package.json └── .eslintrc /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /npm-debug.log 3 | /build 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "sourceMaps": true, 3 | "presets": [ 4 | ["es2015", { "loose":true }], 5 | "stage-0" 6 | ], 7 | "plugins": [ 8 | "styled-jsx/babel", 9 | ["transform-react-jsx", { "pragma": "h" }] 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | end_of_line = lf 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [{package.json,.*rc,*.yml}] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { h, render } from 'preact'; 2 | 3 | Object.defineProperty(h().constructor.prototype, 'props', { enumerable:true, get(){ return this.attributes; } }); 4 | 5 | let root; 6 | function init() { 7 | let App = require('./components/app').default; 8 | root = render(, document.body, root); 9 | } 10 | init(); 11 | 12 | // HMR: 13 | if (module.hot) module.hot.accept('./components/app', init); 14 | -------------------------------------------------------------------------------- /src/components/home.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | 3 | export default class Home extends Component { 4 | render() { 5 | return ( 6 |
7 | 14 | 15 |

Home

16 | 17 |

This is the Home component.

18 |
19 | ); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Preact] + [styled-jsx] Demo 2 | 3 | Just a simple demo showing [preact-boilerplate] converted over to [styled-jsx], running without [preact-compat]. 4 | 5 | **Demo:** https://preact-styled-jsx-demo.now.sh 6 | 7 | --- 8 | 9 | 10 | ## License 11 | 12 | MIT 13 | 14 | 15 | [Preact]: https://github.com/developit/preact 16 | [preact-compat]: https://github.com/developit/preact-compat 17 | [styled-jsx]: https://github.com/zeit/styled-jsx 18 | -------------------------------------------------------------------------------- /webpack.config.babel.js: -------------------------------------------------------------------------------- 1 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 2 | import path from 'path'; 3 | 4 | const file = name => path.resolve(__dirname, name); 5 | 6 | module.exports = { 7 | context: file('src'), 8 | entry: './index.js', 9 | 10 | output: { 11 | path: file('build'), 12 | publicPath: '/', 13 | filename: 'bundle.js' 14 | }, 15 | 16 | resolve: { 17 | alias: { 18 | // all that's needed to make styled-jsx work: 19 | 'react': 'preact' 20 | } 21 | }, 22 | 23 | module: { 24 | loaders: [ 25 | { 26 | test: /\.jsx?$/, 27 | exclude: /node_modules/, 28 | loader: 'babel' 29 | } 30 | ] 31 | }, 32 | 33 | plugins: [ 34 | new HtmlWebpackPlugin({ 35 | minify: { collapseWhitespace: true } 36 | }) 37 | ], 38 | 39 | node: false, 40 | 41 | devtool: 'source-map', 42 | 43 | devServer: { 44 | port: process.env.PORT || 8080, 45 | publicPath: '/', 46 | contentBase: './src', 47 | historyApiFallback: true 48 | } 49 | }; 50 | -------------------------------------------------------------------------------- /src/components/app.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import { Router } from 'preact-router'; 3 | 4 | import Header from './header'; 5 | import Home from './home'; 6 | import Profile from './profile'; 7 | 8 | export default class App extends Component { 9 | render() { 10 | return ( 11 |
12 | 34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 |
43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "preact-styled-jsx-demo", 3 | "version": "1.0.0", 4 | "description": "Example of using preact + styled-jsx", 5 | "scripts": { 6 | "dev": "webpack-dev-server --inline --hot --progress", 7 | "start": "serve build -s -c 1", 8 | "prestart": "npm run build", 9 | "build": "webpack -p --progress", 10 | "test": "eslint {src,test}" 11 | }, 12 | "keywords": [ 13 | "preact", 14 | "boilerplate", 15 | "webpack" 16 | ], 17 | "license": "MIT", 18 | "author": "Jason Miller ", 19 | "devDependencies": { 20 | "babel": "^6.5.2", 21 | "babel-core": "^6.14.0", 22 | "babel-eslint": "^7.0.0", 23 | "babel-loader": "^6.2.5", 24 | "babel-plugin-transform-react-jsx": "^6.8.0", 25 | "babel-preset-es2015": "^6.14.0", 26 | "babel-preset-stage-0": "^6.5.0", 27 | "eslint": "^3.0.1", 28 | "html-webpack-plugin": "^2.22.0", 29 | "webpack": "^1.13.2", 30 | "webpack-dev-server": "^1.15.0" 31 | }, 32 | "dependencies": { 33 | "preact": "^6.0.0", 34 | "preact-router": "^2.0.0", 35 | "serve": "^2.0.0", 36 | "styled-jsx": "^0.1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/components/profile.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | 3 | export default class Profile extends Component { 4 | state = { 5 | count: 0 6 | }; 7 | 8 | // gets called when this route is navigated to 9 | componentDidMount() { 10 | // start a timer for the clock: 11 | this.timer = setInterval(::this.updateTime, 1000); 12 | this.updateTime(); 13 | 14 | // every time we get remounted, increment a counter: 15 | this.setState({ count: this.state.count+1 }); 16 | } 17 | 18 | // gets called just before navigating away from the route 19 | componentWillUnmount() { 20 | clearInterval(this.timer); 21 | } 22 | 23 | // update the current time 24 | updateTime() { 25 | let time = new Date().toLocaleString(); 26 | this.setState({ time }); 27 | } 28 | 29 | // Note: `user` comes from the URL, courtesy of our router 30 | render({ user }, { time, count }) { 31 | return ( 32 |
33 | 41 | 42 |

Profile: { user }

43 | 44 |

This is the user profile for a user named { user }.

45 | 46 |
Current time: { time }
47 | 48 |
Profile route mounted { count } times.
49 |
50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/components/header.js: -------------------------------------------------------------------------------- 1 | import { h, Component } from 'preact'; 2 | import { Link } from 'preact-router'; 3 | 4 | export default class Header extends Component { 5 | render() { 6 | return ( 7 |
8 | 53 | 54 |

Preact App

55 | 56 | 61 |
62 | ); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "eslint:recommended", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "mocha": true, 8 | "es6": true 9 | }, 10 | "parserOptions": { 11 | "ecmaFeatures": { 12 | "modules": true, 13 | "jsx": true 14 | } 15 | }, 16 | "globals": {}, 17 | "rules": { 18 | "no-empty": 0, 19 | "no-console": 0, 20 | "no-empty-pattern": 0, 21 | "no-unused-vars": [0, { "varsIgnorePattern": "^h$" }], 22 | "no-cond-assign": 1, 23 | "semi": 2, 24 | "camelcase": 0, 25 | "comma-style": 2, 26 | "comma-dangle": [2, "never"], 27 | "indent": [2, "tab", {"SwitchCase": 1}], 28 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"], 29 | "no-trailing-spaces": [2, { "skipBlankLines": true }], 30 | "max-nested-callbacks": [2, 3], 31 | "no-eval": 2, 32 | "no-implied-eval": 2, 33 | "no-new-func": 2, 34 | "guard-for-in": 2, 35 | "eqeqeq": 1, 36 | "no-else-return": 2, 37 | "no-redeclare": 2, 38 | "no-dupe-keys": 2, 39 | "radix": 2, 40 | "strict": [2, "never"], 41 | "no-shadow": 0, 42 | "no-delete-var": 2, 43 | "no-undef-init": 2, 44 | "no-shadow-restricted-names": 2, 45 | "handle-callback-err": 0, 46 | "no-lonely-if": 2, 47 | "keyword-spacing": 2, 48 | "constructor-super": 2, 49 | "no-this-before-super": 2, 50 | "no-dupe-class-members": 2, 51 | "no-const-assign": 2, 52 | "prefer-spread": 2, 53 | "no-useless-concat": 2, 54 | "no-var": 2, 55 | "object-shorthand": 2, 56 | "prefer-arrow-callback": 2 57 | } 58 | } 59 | --------------------------------------------------------------------------------