Skip to content

Single page preact web applications for embedded into ESP8266 and ESP32

License

Notifications You must be signed in to change notification settings

tonilopezmr/embedded-preact-template

Repository files navigation

Embedded Preact Template

Template of preactjs to create a single page application, and inline everything in one HTML file optimized to execute it on the esp8266. This template is based on configduino-sample, which is a sample of a npm library called configuino.

Setup

Install dependencies:

yarn install

Run webserver locally to check everything is working:

yarn start

It will start the server at http://localhost:8080.

Building

To build, run yarn build which will output all the HTML, CSS, JS, and index.html.gz.h file to flash it into the ESP8266 or ESP32 as source code.

The index.html file will also have all the CSS and JS mashed into it, so it is completely standalone - all you need to do is open it in a browser.

All compiled sources will be placed in build folder and the .h file into build/out folder.

Webpack file

Import webpack, and the plugins we need

import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import HtmlWebpackInlineSourcePlugin from 'html-webpack-inline-source-plugin';
import path from 'path';
const ENV = process.env.NODE_ENV || 'development';
module.exports = {
  context: path.resolve(__dirname, "src"),
  entry: './index.js',

Set the JavaScript output file to bundle.js in the build directory

  output: {
    path: path.resolve(__dirname, "build"),
    publicPath: '/',
    filename: 'bundle.js'
  },

Tell webpack where to find include files.

  resolve: {
    extensions: ['.jsx', '.js' ],
    modules: [
      path.resolve(__dirname, "src/lib"),
      path.resolve(__dirname, "node_modules"),
      'node_modules'
    ]
  },

Tell Webpack to use babel-loader for .js and .jsx files, and css-loader for .css files

css-loader is configured to use CSS modules and to use short class names in production.

  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: "style-loader",
          use: "css-loader?modules&localIdentName=" + (ENV == 'production' ? "[hash:base64:4]" : "[name]__[local]___[hash:base64:5]")
        })
      },
    ]
  },

Tell Extract Text Plugin to output all compiled CSS to style.css, and tell the HTML plugin to compile index.ejs.

Finally, inline the CSS and JS into the HTML file.

  plugins: ([
    new webpack.NoEmitOnErrorsPlugin(),
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify(ENV)
    }),
    new ExtractTextPlugin({ filename: 'style.css', allChunks: true, disable: ENV !== 'production' }),
    new HtmlWebpackPlugin({
      template: './index.ejs',
      minify: { collapseWhitespace: true },
      inlineSource: '(.js|.css)$'
    }),
    new HtmlWebpackInlineSourcePlugin()
  ]),
  stats: { colors: true },

  node: {
    global: true,
    process: false,
    Buffer: false,
    __filename: false,
    __dirname: false,
    setImmediate: false
  }
};

index.ejs

This file will be compiled into an HTML file. It gets the file names generated by the HTML plugin and injects them as script and link tags. You probably won't need to change this file too much.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<% if(process.env.NODE_ENV != 'production') { %>
<% for (var chunk in htmlWebpackPlugin.files.css) { %>
  <link rel="preload" href="<%= htmlWebpackPlugin.files.css[chunk] %>"  as="style">
<% } %>
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
  <link rel="preload" href="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>" as="script">
<% } %>
<% } %>
</head>
<body></body>
</html>

index.js

This is the entry point for preact. It simply attaches to the component generated by app.js to the DOM.

Attaching to document.body is not usually a good idea, but in this case, there is no chance of external third-party scripts messing with the DOM.

import './style.css';
import { Component, h, render } from 'preact';

class App extends Component {

  render() {
    return (
      <div>
        <p>Embedded Preact template is working!</p>
      </div>
    );
  }

}

render(<App />, document.body);

Embed images

If you want to display some image you need to embed that image into the single HTML to have only one file, to that you need to convert your images into base64 strings, then you can copy it to your HTML or CSS files like this:

div.image {
  width: 60px;
  height: 4px;
  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIA...);
}

About

Single page preact web applications for embedded into ESP8266 and ESP32

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published