Fix Hass.io build script (#405)

This commit is contained in:
Paulus Schoutsen
2017-08-21 22:44:20 -07:00
committed by GitHub
parent c289f6c925
commit 9b9cba86c2
9 changed files with 238 additions and 443 deletions
+5
View File
@@ -0,0 +1,5 @@
{
"rules": {
"no-restricted-syntax": 0
}
}
+58
View File
@@ -0,0 +1,58 @@
const {
Analyzer,
FSUrlLoader
} = require('polymer-analyzer');
const Bundler = require('polymer-bundler').Bundler;
const parse5 = require('parse5');
const { streamFromString } = require('./stream');
// Bundle an HTML file and convert it to a stream
async function bundledStreamFromHTML(path, bundlerOptions = {}) {
const bundler = new Bundler(bundlerOptions);
const manifest = await bundler.generateManifest([path]);
const result = await bundler.bundle(manifest);
return streamFromString(
path, parse5.serialize(result.documents.get(path).ast));
}
async function analyze(root, paths) {
const analyzer = new Analyzer({
urlLoader: new FSUrlLoader(root),
});
return analyzer.analyze(paths);
}
async function findDependencies(root, element) {
const deps = new Set();
async function resolve(files) {
const analysis = await analyze(root, files);
const toResolve = [];
for (const file of files) {
const doc = analysis.getDocument(file);
for (const importEl of doc.getFeatures({ kind: 'import' })) {
const url = importEl.url;
if (!deps.has(url)) {
deps.add(url);
toResolve.push(url);
}
}
}
if (toResolve.length > 0) {
return resolve(toResolve);
}
}
await resolve([element]);
return deps;
}
module.exports = {
bundledStreamFromHTML,
findDependencies,
};
+33
View File
@@ -0,0 +1,33 @@
/**
* Polymer build strategy to strip imports, even if explictely imported
*/
module.exports.stripImportsStrategy = function (urls) {
return (bundles) => {
for (const bundle of bundles) {
for (const url of urls) {
bundle.stripImports.add(url);
}
}
return bundles;
};
};
/**
* Polymer build strategy to strip everything but the entrypoints
* for bundles that match a specific entry point.
*/
module.exports.stripAllButEntrypointStrategy = function (entryPoint) {
return (bundles) => {
for (const bundle of bundles) {
if (bundle.entrypoints.size === 1 &&
bundle.entrypoints.has(entryPoint)) {
for (const file of bundle.files) {
if (!bundle.entrypoints.has(file)) {
bundle.stripImports.add(file);
}
}
}
}
return bundles;
};
};
+21
View File
@@ -0,0 +1,21 @@
const stream = require('stream');
const gutil = require('gulp-util');
function streamFromString(filename, string) {
var src = stream.Readable({ objectMode: true });
src._read = function () {
this.push(new gutil.File({
cwd: '',
base: '',
path: filename,
contents: new Buffer(string)
}));
this.push(null);
};
return src;
}
module.exports = {
streamFromString,
};
+27
View File
@@ -0,0 +1,27 @@
const gulpif = require('gulp-if');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const { gulp: cssSlam } = require('css-slam');
const htmlMinifier = require('gulp-html-minifier');
const { HtmlSplitter } = require('polymer-build');
module.exports.minifyStream = function (stream) {
const sourcesHtmlSplitter = new HtmlSplitter();
return stream
.pipe(sourcesHtmlSplitter.split())
.pipe(gulpif(/[^app]\.js$/, babel({
sourceType: 'script',
presets: [
['es2015', { modules: false }]
]
})))
.pipe(gulpif(/\.js$/, uglify({ sourceMap: false })))
.pipe(gulpif(/\.css$/, cssSlam()))
.pipe(gulpif(/\.html$/, cssSlam()))
.pipe(gulpif(/\.html$/, htmlMinifier({
collapseWhitespace: true,
removeComments: true
})))
.pipe(sourcesHtmlSplitter.rejoin());
};
+8 -62
View File
@@ -1,11 +1,6 @@
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const { gulp: cssSlam } = require('css-slam');
const gulp = require('gulp');
const filter = require('gulp-filter');
const htmlMinifier = require('gulp-html-minifier');
const gulpif = require('gulp-if');
const { PolymerProject, HtmlSplitter } = require('polymer-build');
const { PolymerProject, } = require('polymer-build');
const {
composeStrategies,
generateShellMergeStrategy,
@@ -15,25 +10,11 @@ const rename = require('gulp-rename');
const polymerConfig = require('../../polymer');
function minifyStream(stream) {
const sourcesHtmlSplitter = new HtmlSplitter();
return stream
.pipe(sourcesHtmlSplitter.split())
.pipe(gulpif(/[^app]\.js$/, babel({
sourceType: 'script',
presets: [
['es2015', { modules: false }]
]
})))
.pipe(gulpif(/\.js$/, uglify({ sourceMap: false })))
.pipe(gulpif(/\.css$/, cssSlam()))
.pipe(gulpif(/\.html$/, cssSlam()))
.pipe(gulpif(/\.html$/, htmlMinifier({
collapseWhitespace: true,
removeComments: true
})))
.pipe(sourcesHtmlSplitter.rejoin());
}
const minifyStream = require('../common/transform').minifyStream;
const {
stripImportsStrategy,
stripAllButEntrypointStrategy
} = require('../common/strategy');
function renamePanel(path) {
// Rename panels to be panels/* and not their subdir
@@ -49,49 +30,14 @@ function renamePanel(path) {
}
}
/**
* Polymer build strategy to strip imports, even if explictely imported
*/
function generateStripStrategy(urls) {
return (bundles) => {
for (const bundle of bundles) {
for (const url of urls) {
bundle.stripImports.add(url);
}
}
return bundles;
};
}
/**
* Polymer build strategy to strip everything but the entrypoints
* for bundles that match a specific entry point.
*/
function stripAllButEntrypoint(entryPoint) {
return (bundles) => {
for (const bundle of bundles) {
if (bundle.entrypoints.size === 1 &&
bundle.entrypoints.has(entryPoint)) {
for (const file of bundle.files) {
if (!bundle.entrypoints.has(file)) {
bundle.stripImports.add(file);
}
}
}
}
return bundles;
};
}
gulp.task('build', ['ru_all'], () => {
const strategy = composeStrategies([
generateShellMergeStrategy(polymerConfig.shell),
generateStripStrategy([
stripImportsStrategy([
'bower_components/font-roboto/roboto.html',
'bower_components/paper-styles/color.html',
]),
stripAllButEntrypoint('panels/hassio/ha-panel-hassio.html')
stripAllButEntrypointStrategy('panels/hassio/ha-panel-hassio.html')
]);
const project = new PolymerProject(polymerConfig);
+34 -65
View File
@@ -1,78 +1,47 @@
/*
TODO:
- Use gulp streams
- Use polymer bundler to vulcanize
*/
var gulp = require('gulp');
var Vulcanize = require('vulcanize');
var minify = require('html-minifier');
var fs = require('fs');
const rename = require('gulp-rename');
function minifyHTML(html) {
return minify.minify(html, {
customAttrAssign: [/\$=/],
removeComments: true,
removeCommentsFromCDATA: true,
removeCDATASectionsFromCDATA: true,
collapseWhitespace: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
minifyJS: true,
minifyCSS: true,
});
}
const {
stripImportsStrategy,
} = require('../common/strategy');
const minifyStream = require('../common/transform').minifyStream;
const {
bundledStreamFromHTML,
findDependencies
} = require('../common/html');
const baseVulcanOptions = {
inlineScripts: true,
inlineCss: true,
implicitStrip: true,
stripComments: true,
};
const { polymer_dir } = require('../config');
const baseExcludes = [
const DEPS_TO_STRIP = [
'bower_components/font-roboto/roboto.html',
'bower_components/paper-styles/color.html',
'bower_components/iron-meta/iron-meta.html',
];
const DEPS_TO_STRIP_RECURSIVELY = [
'bower_components/polymer/polymer.html',
];
const toProcess = [
// This is the Hass.io configuration panel
// It's build standalone because it is embedded in the supervisor.
{
source: './panels/hassio/hassio-main.html',
output: './build-temp/hassio-main.html',
vulcan: new Vulcanize(Object.assign({}, baseVulcanOptions, {
stripExcludes: baseExcludes.concat([
'bower_components/polymer/polymer.html',
'bower_components/iron-meta/iron-meta.html',
]),
})),
},
];
gulp.task(
'hassio-panel',
async () => {
const toStrip = [...DEPS_TO_STRIP];
function vulcanizeEntry(entry) {
return new Promise((resolve, reject) => {
console.log('Processing', entry.source);
entry.vulcan.process(entry.source, (err, inlinedHtml) => {
if (err !== null) {
reject(`${entry.source}: ${err}`);
return;
for (let dep of DEPS_TO_STRIP_RECURSIVELY) {
toStrip.push(dep);
const deps = await findDependencies(polymer_dir, dep);
for (const importUrl of deps) {
toStrip.push(importUrl);
}
}
console.log('Writing', entry.output);
fs.writeFileSync(entry.output, minifyHTML(inlinedHtml));
resolve();
});
});
}
const stream = await bundledStreamFromHTML(
'panels/hassio/hassio-main.html', {
strategy: stripImportsStrategy(toStrip)
}
);
gulp.task('hassio-panel', () => {
if (!fs.existsSync('build-temp')) {
fs.mkdirSync('build-temp');
return minifyStream(stream)
.pipe(rename('hassio-main.html'))
.pipe(gulp.dest('build-temp/'));
}
toProcess.reduce(
(p, entry) => p.then(() => vulcanizeEntry(entry)),
Promise.resolve());
return toProcess;
});
);