Migrate demo to gulp (#3152)

* Migrate demo to gulp

* Tweak demo migration to gulp

* Feature detect demo

* Gen icons
This commit is contained in:
Paulus Schoutsen 2019-05-02 22:41:58 -07:00 committed by GitHub
parent 530be9155b
commit 34129cc7cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 312 additions and 211 deletions

View File

@ -10,18 +10,34 @@ require("./service-worker.js");
require("./entry-html.js");
gulp.task(
"build-release",
"develop-app",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "development";
},
"clean",
gulp.parallel(
"gen-service-worker-dev",
"gen-icons",
"gen-pages-dev",
"gen-index-html-dev",
"build-translations"
),
"copy-static",
"webpack-watch-app"
)
);
gulp.task(
"build-app",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
"clean",
gulp.parallel(
"copy-static",
"gen-icons",
gulp.series("build-translations", "copy-translations")
),
gulp.parallel("webpack-prod", "compress-static"),
gulp.parallel("gen-icons", "build-translations"),
"copy-static",
gulp.parallel("webpack-prod-app", "compress-static"),
gulp.parallel(
"gen-pages-prod",
"gen-index-html-prod",

View File

@ -3,3 +3,4 @@ const gulp = require("gulp");
const config = require("../paths");
gulp.task("clean", () => del([config.root, config.build_dir]));
gulp.task("clean-demo", () => del([config.demo_root, config.build_dir]));

View File

@ -0,0 +1,36 @@
// Run HA develop mode
const gulp = require("gulp");
require("./clean.js");
require("./translations.js");
require("./gen-icons.js");
require("./gather-static.js");
require("./webpack.js");
require("./service-worker.js");
require("./entry-html.js");
gulp.task(
"develop-demo",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "development";
},
"clean-demo",
gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"),
"copy-static-demo",
"webpack-dev-server-demo"
)
);
gulp.task(
"build-demo",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "production";
},
"clean-demo",
gulp.parallel("gen-icons", "gen-icons-demo", "build-translations"),
"copy-static-demo",
"webpack-prod-demo"
)
);

View File

@ -1,29 +0,0 @@
// Run HA develop mode
const gulp = require("gulp");
require("./clean.js");
require("./translations.js");
require("./gen-icons.js");
require("./gather-static.js");
require("./webpack.js");
require("./service-worker.js");
require("./entry-html.js");
gulp.task(
"develop",
gulp.series(
async function setEnv() {
process.env.NODE_ENV = "development";
},
"clean",
gulp.parallel(
"copy-static",
"gen-service-worker-dev",
"gen-icons",
"gen-pages-dev",
"gen-index-html-dev",
gulp.series("build-translations", "copy-translations")
),
"webpack-watch"
)
);

View File

@ -5,17 +5,21 @@ const path = require("path");
const fs = require("fs-extra");
const zopfli = require("gulp-zopfli-green");
const merge = require("merge-stream");
const config = require("../paths");
const paths = require("../paths");
const npmPath = (...parts) =>
path.resolve(config.polymer_dir, "node_modules", ...parts);
const polyPath = (...parts) => path.resolve(config.polymer_dir, ...parts);
const staticPath = (...parts) => path.resolve(config.root, "static", ...parts);
path.resolve(paths.polymer_dir, "node_modules", ...parts);
const polyPath = (...parts) => path.resolve(paths.polymer_dir, ...parts);
const copyFileDir = (fromFile, toDir) =>
fs.copySync(fromFile, path.join(toDir, path.basename(fromFile)));
function copyTranslations() {
const genStaticPath = (staticDir) => (...parts) =>
path.resolve(staticDir, ...parts);
function copyTranslations(staticDir) {
const staticPath = genStaticPath(staticDir);
// Translation output
fs.copySync(
polyPath("build-translations/output"),
@ -23,9 +27,8 @@ function copyTranslations() {
);
}
function copyStatic() {
// Basic static files
fs.copySync(polyPath("public"), config.root);
function copyPolyfills(staticDir) {
const staticPath = genStaticPath(staticDir);
// Web Component polyfills and adapters
copyFileDir(
@ -40,31 +43,16 @@ function copyStatic() {
npmPath("@webcomponents/webcomponentsjs/webcomponents-bundle.js.map"),
staticPath("polyfills/")
);
// Local fonts
fs.copySync(npmPath("@polymer/font-roboto-local/fonts"), staticPath("fonts"));
// External dependency assets
copyFileDir(
npmPath("react-big-calendar/lib/css/react-big-calendar.css"),
staticPath("panels/calendar/")
);
copyFileDir(
npmPath("leaflet/dist/leaflet.css"),
staticPath("images/leaflet/")
);
fs.copySync(
npmPath("leaflet/dist/images"),
staticPath("images/leaflet/images/")
);
}
gulp.task("copy-static", (done) => {
copyStatic();
done();
});
function copyFonts(staticDir) {
const staticPath = genStaticPath(staticDir);
// Local fonts
fs.copySync(npmPath("@polymer/font-roboto-local/fonts"), staticPath("fonts"));
}
gulp.task("compress-static", () => {
function compressStatic(staticDir) {
const staticPath = genStaticPath(staticDir);
const fonts = gulp
.src(staticPath("fonts/**/*.ttf"))
.pipe(zopfli())
@ -79,9 +67,44 @@ gulp.task("compress-static", () => {
.pipe(gulp.dest(staticPath("translations")));
return merge(fonts, polyfills, translations);
});
}
gulp.task("copy-translations", (done) => {
copyTranslations();
gulp.task("copy-static", (done) => {
const staticDir = paths.static;
const staticPath = genStaticPath(paths.static);
// Basic static files
fs.copySync(polyPath("public"), paths.root);
copyPolyfills(staticDir);
copyFonts(staticDir);
copyTranslations(staticDir);
// Panel assets
copyFileDir(
npmPath("react-big-calendar/lib/css/react-big-calendar.css"),
staticPath("panels/calendar/")
);
copyFileDir(
npmPath("leaflet/dist/leaflet.css"),
staticPath("images/leaflet/")
);
fs.copySync(
npmPath("leaflet/dist/images"),
staticPath("images/leaflet/images/")
);
done();
});
gulp.task("compress-static", () => compressStatic(paths.root));
gulp.task("copy-static-demo", (done) => {
// Copy app static files
fs.copySync(polyPath("public"), paths.demo_root);
// Copy demo static files
fs.copySync(path.resolve(paths.demo_dir, "public"), paths.demo_root);
copyPolyfills(paths.demo_static);
copyFonts(paths.demo_static);
copyTranslations(paths.demo_static);
done();
});

View File

@ -1,6 +1,7 @@
const gulp = require("gulp");
const path = require("path");
const fs = require("fs");
const paths = require("../paths");
const ICON_PACKAGE_PATH = path.resolve(
__dirname,
@ -118,6 +119,15 @@ gulp.task("gen-icons-hass", (done) => {
});
gulp.task("gen-icons", gulp.series("gen-icons-hass", "gen-icons-mdi"));
gulp.task("gen-icons-demo", (done) => {
const iconNames = findIcons(path.resolve(paths.demo_dir, "./src"), "hademo");
fs.writeFileSync(
path.resolve(paths.demo_dir, "hademo-icons.html"),
generateIconset("hademo", iconNames)
);
done();
});
module.exports = {
findIcons,
generateIconset,

View File

@ -1,7 +1,11 @@
// Tasks to run webpack.
const gulp = require("gulp");
const path = require("path");
const webpack = require("webpack");
const { createAppConfig } = require("../webpack");
const WebpackDevServer = require("webpack-dev-server");
const log = require("fancy-log");
const paths = require("../paths");
const { createAppConfig, createDemoConfig } = require("../webpack");
const handler = (done) => (err, stats) => {
if (err) {
@ -12,7 +16,7 @@ const handler = (done) => (err, stats) => {
return;
}
console.log(`Build done @ ${new Date().toLocaleTimeString()}`);
log(`Build done @ ${new Date().toLocaleTimeString()}`);
if (stats.hasErrors() || stats.hasWarnings()) {
console.log(stats.toString("minimal"));
@ -23,7 +27,7 @@ const handler = (done) => (err, stats) => {
}
};
gulp.task("webpack-watch", () => {
gulp.task("webpack-watch-app", () => {
const compiler = webpack([
createAppConfig({
isProdBuild: false,
@ -41,7 +45,7 @@ gulp.task("webpack-watch", () => {
});
gulp.task(
"webpack-prod",
"webpack-prod-app",
() =>
new Promise((resolve) =>
webpack(
@ -61,3 +65,52 @@ gulp.task(
)
)
);
gulp.task("webpack-dev-server-demo", () => {
const compiler = webpack([
createDemoConfig({
isProdBuild: false,
latestBuild: false,
isStatsBuild: false,
}),
createDemoConfig({
isProdBuild: false,
latestBuild: true,
isStatsBuild: false,
}),
]);
new WebpackDevServer(compiler, {
open: true,
watchContentBase: true,
contentBase: path.resolve(paths.demo_dir, "dist"),
}).listen(8080, "localhost", function(err) {
if (err) {
throw err;
}
// Server listening
log("[webpack-dev-server]", "http://localhost:8080");
});
});
gulp.task(
"webpack-prod-demo",
() =>
new Promise((resolve) =>
webpack(
[
createDemoConfig({
isProdBuild: true,
latestBuild: false,
isStatsBuild: false,
}),
createDemoConfig({
isProdBuild: true,
latestBuild: true,
isStatsBuild: false,
}),
],
handler(resolve)
)
)
);

View File

@ -2,9 +2,16 @@ var path = require("path");
module.exports = {
polymer_dir: path.resolve(__dirname, ".."),
build_dir: path.resolve(__dirname, "../build"),
root: path.resolve(__dirname, "../hass_frontend"),
static: path.resolve(__dirname, "../hass_frontend/static"),
output: path.resolve(__dirname, "../hass_frontend/frontend_latest"),
output_es5: path.resolve(__dirname, "../hass_frontend/frontend_es5"),
demo_dir: path.resolve(__dirname, "../demo"),
demo_root: path.resolve(__dirname, "../demo/dist"),
demo_static: path.resolve(__dirname, "../demo/dist/static"),
demo_output: path.resolve(__dirname, "../demo/dist/frontend_latest"),
demo_output_es5: path.resolve(__dirname, "../demo/frontend_es5"),
};

View File

@ -17,6 +17,12 @@ if (!version) {
}
version = version[0];
const genMode = (isProdBuild) => (isProdBuild ? "production" : "development");
const genDevTool = (isProdBuild) =>
isProdBuild ? "cheap-source-map" : "inline-cheap-module-source-map";
const genChunkFilename = (isProdBuild, isStatsBuild) =>
isProdBuild && !isStatsBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
const resolve = {
extensions: [".ts", ".js", ".json", ".tsx"],
alias: {
@ -29,6 +35,20 @@ const resolve = {
},
};
const cssLoader = {
test: /\.css$/,
use: "raw-loader",
};
const htmlLoader = {
test: /\.(html)$/,
use: {
loader: "html-loader",
options: {
exportAsEs6Default: true,
},
},
};
const plugins = [
// Ignore moment.js locales
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
@ -75,8 +95,6 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
] = `build-translations/output/${key}.json`;
});
const publicPath = latestBuild ? "/frontend_latest/" : "/frontend_es5/";
const entry = {
app: "./src/entrypoints/app.ts",
authorize: "./src/entrypoints/authorize.ts",
@ -88,28 +106,11 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
};
return {
mode: isProdBuild ? "production" : "development",
devtool: isProdBuild
? "cheap-source-map "
: "inline-cheap-module-source-map",
mode: genMode(isProdBuild),
devtool: genDevTool(isProdBuild),
entry,
module: {
rules: [
babelLoaderConfig({ latestBuild }),
{
test: /\.css$/,
use: "raw-loader",
},
{
test: /\.(html)$/,
use: {
loader: "html-loader",
options: {
exportAsEs6Default: true,
},
},
},
],
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
},
optimization: optimization(latestBuild),
plugins: [
@ -165,20 +166,56 @@ const createAppConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
if (!isProdBuild || dontHash.has(chunk.name)) return `${chunk.name}.js`;
return `${chunk.name}.${chunk.hash.substr(0, 8)}.js`;
},
chunkFilename:
isProdBuild && !isStatsBuild
? "chunk.[chunkhash].js"
: "[name].chunk.js",
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
path: latestBuild ? paths.output : paths.output_es5,
publicPath,
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
},
resolve,
};
};
const createDemoConfig = ({ isProdBuild, latestBuild, isStatsBuild }) => {
return {
mode: genMode(isProdBuild),
devtool: genDevTool(isProdBuild),
entry: {
main: "./demo/src/entrypoint.ts",
compatibility: "./src/entrypoints/compatibility.ts",
},
module: {
rules: [babelLoaderConfig({ latestBuild }), cssLoader, htmlLoader],
},
optimization: optimization(latestBuild),
plugins: [
new webpack.DefinePlugin({
__DEV__: !isProdBuild,
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
__VERSION__: JSON.stringify("DEMO"),
__DEMO__: true,
__STATIC_PATH__: "/static/",
"process.env.NODE_ENV": JSON.stringify(
isProdBuild ? "production" : "development"
),
}),
...plugins,
].filter(Boolean),
resolve,
output: {
filename: "[name].js",
chunkFilename: genChunkFilename(isProdBuild, isStatsBuild),
path: path.resolve(
paths.demo_root,
latestBuild ? "frontend_latest" : "frontend_es5"
),
publicPath: latestBuild ? "/frontend_latest/" : "/frontend_es5/",
},
};
};
module.exports = {
resolve,
plugins,
optimization,
createAppConfig,
createDemoConfig,
};

View File

@ -74,9 +74,6 @@
content="https://www.home-assistant.io/images/default-social.png"
/>
<title>Home Assistant Demo</title>
<script src="./custom-elements-es5-adapter.js"></script>
<script src="./compatibility.js"></script>
<script src="./main.js" async></script>
<style>
body {
font-family: Roboto, Noto, sans-serif;
@ -98,6 +95,47 @@
<body>
<div id="ha-init-skeleton"></div>
<ha-demo></ha-demo>
<script>
function _ls(src) {
var doc = document.documentElement;
var script = doc.insertBefore(
document.createElement("script"),
doc.lastChild
);
script.type = "text/javascript";
script.src = src;
}
window.Polymer = {
lazyRegister: true,
useNativeCSSProperties: true,
dom: "shadow",
suppressTemplateNotifications: true,
suppressBindingNotifications: true,
};
var webComponentsSupported =
"customElements" in window &&
"content" in document.createElement("template");
if (!webComponentsSupported) {
_ls("/static/polyfills/webcomponents-bundle.js");
}
var isS101 = /\s+Version\/10\.1(?:\.\d+)?\s+Safari\//.test(
navigator.userAgent
);
</script>
<script type="module" src="./frontend_latest/main.js"></script>
<script nomodule>
(function() {
// // Safari 10.1 supports type=module but ignores nomodule, so we add this check.
if (!isS101) {
_ls("./static/polyfills/custom-elements-es5-adapter.js");
_ls("./frontend_es5/compatibility.js");
_ls("./frontend_es5/main.js");
}
})();
</script>
<script>
var _gaq = [["_setAccount", "UA-57927901-5"], ["_trackPageview"]];
(function(d, t) {

View File

View File

@ -4,16 +4,6 @@
# Stop on errors
set -e
cd "$(dirname "$0")/.."
cd "$(dirname "$0")/../.."
OUTPUT_DIR=dist
rm -rf $OUTPUT_DIR
mkdir $OUTPUT_DIR
node script/gen-icons.js
cd ..
DEMO=1 ./node_modules/.bin/gulp build-translations gen-icons
cd demo
NODE_ENV=production ../node_modules/.bin/webpack -p --config webpack.config.js
./node_modules/.bin/gulp build-demo

View File

@ -4,12 +4,6 @@
# Stop on errors
set -e
cd "$(dirname "$0")/.."
cd "$(dirname "$0")/../.."
node script/gen-icons.js
cd ..
DEMO=1 ./node_modules/.bin/gulp build-translations gen-icons
cd demo
../node_modules/.bin/webpack-dev-server
./node_modules/.bin/gulp develop-demo

View File

@ -1,90 +1,13 @@
const path = require("path");
const webpack = require("webpack");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const WorkboxPlugin = require("workbox-webpack-plugin");
const { babelLoaderConfig } = require("../build-scripts/babel.js");
const webpackBase = require("../build-scripts/webpack.js");
const { createDemoConfig } = require("../build-scripts/webpack.js");
const isProd = process.env.NODE_ENV === "production";
// This file exists because we haven't migrated the stats script yet
const isProdBuild = process.env.NODE_ENV === "production";
const isStatsBuild = process.env.STATS === "1";
const chunkFilename =
isProd && !isStatsBuild ? "chunk.[chunkhash].js" : "[name].chunk.js";
const buildPath = path.resolve(__dirname, "dist");
const publicPath = "/";
const latestBuild = false;
module.exports = {
mode: isProd ? "production" : "development",
devtool: isProd ? "cheap-source-map" : "inline-source-map",
entry: {
main: "./src/entrypoint.ts",
compatibility: "../src/entrypoints/compatibility.ts",
},
module: {
rules: [
babelLoaderConfig({ latestBuild }),
{
test: /\.css$/,
use: "raw-loader",
},
{
test: /\.(html)$/,
use: {
loader: "html-loader",
options: {
exportAsEs6Default: true,
},
},
},
],
},
optimization: webpackBase.optimization(latestBuild),
plugins: [
new webpack.DefinePlugin({
__DEV__: false,
__BUILD__: JSON.stringify(latestBuild ? "latest" : "es5"),
__VERSION__: JSON.stringify("DEMO"),
__DEMO__: true,
__STATIC_PATH__: "/static/",
"process.env.NODE_ENV": JSON.stringify(
isProd ? "production" : "development"
),
}),
new CopyWebpackPlugin([
"public",
"../node_modules/@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js",
{ from: "../public", to: "static" },
{ from: "../build-translations/output", to: "static/translations" },
{
from: "../node_modules/leaflet/dist/leaflet.css",
to: "static/images/leaflet/",
},
{
from: "../node_modules/@polymer/font-roboto-local/fonts",
to: "static/fonts",
},
{
from: "../node_modules/leaflet/dist/images",
to: "static/images/leaflet/",
},
]),
...webpackBase.plugins,
isProd &&
new WorkboxPlugin.GenerateSW({
swDest: "service_worker.js",
importWorkboxFrom: "local",
include: [],
}),
].filter(Boolean),
resolve: webpackBase.resolve,
output: {
filename: "[name].js",
chunkFilename: chunkFilename,
path: buildPath,
publicPath,
},
devServer: {
contentBase: "./public",
},
};
module.exports = createDemoConfig({
isProdBuild,
isStatsBuild,
latestBuild,
});

View File

@ -6,4 +6,4 @@ set -e
cd "$(dirname "$0")/.."
./node_modules/.bin/gulp build-release
./node_modules/.bin/gulp build-app

View File

@ -6,4 +6,4 @@ set -e
cd "$(dirname "$0")/.."
./node_modules/.bin/gulp develop
./node_modules/.bin/gulp develop-app

View File

@ -1,5 +1,7 @@
const { createAppConfig } = require("./build-scripts/webpack.js");
// This file exists because we haven't migrated the stats script yet
const isProdBuild = process.env.NODE_ENV === "production";
const isStatsBuild = process.env.STATS === "1";