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.
Install dependencies:
yarn install
Run webserver locally to check everything is working:
yarn start
It will start the server at http://localhost:8080
.
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.
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
}
};
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>
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);
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...);
}