Minify HTML, but don't touch PHP with Gulp - javascript

The problem
I have a lot of .php files, mostly containing HTML, but also some PHP lines on top (e.g. form trigger code or similar). So they look like
<?php
if($someValue){
//doSth
}
//more content
?>
<!DOCTYPE html>
<html lang="de">
<head>
<title>My Website</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- Content and scripts here -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
</body>
</html>
The goal
My goal is to minify the HTML (and maybe even the inline javascript, but that's just a little extra), without touching the PHP on top.
I'm using Gulp as automated build tool and would like to see a solution using this tool and any extra packages as they are needed.

The gulp-htmlmin module uses the html-minifier module, which has plenty of options (displayed on both its npmjs.com and github pages) that can be used. The option we will focus on is ignoreCustomFragments.
var gulp = require(gulp),
htmlmin = require(gulp-htmlmin);
gulp.task('htmltask', function(){
return gulp.src(['./dev/*.html','./dev/*.php'])
.pipe(htmlmin({
collapseWhitespace: true,
ignoreCustomFragments: [ /<%[\s\S]*?%>/, /<\?[=|php]?[\s\S]*?\?>/ ]
}))
.pipe(gulp.dest('./site'));
});
In the above code, you see we are using ignoreCustomFragments with the regex /<\?[=|php]?[\s\S]*?\?>/ to ignore code starting with <? and <?php and ending with ?>.
By default, html-minifier ignores php, so you don't have to worry about setting ignoreCustomFragments.
EDIT
Thanks amersk
Some php files you work with may not have closing tags, for example many WordPress files do not. An alternative would be to use the following instead:
ignoreCustomFragments: [/<\?[\s\S]*?(?:\?>|$)/]

This works for me !
// Gulp.js configuration
var
// modules
gulp = require('gulp'),
newer = require('gulp-newer'),
htmlmin = require('gulp-htmlmin')
// development mode?
devBuild = (process.env.NODE_ENV !== 'production'),
// folders
folder = {
src: 'src/',
build: 'build/'
}
gulp.task('minify', () => {
return gulp.src('src/*.html')
.pipe(htmlmin({ collapseWhitespace: true }))
.pipe(gulp.dest('dist'));
});
;

Related

Including node modules to load local CSV file and run wink-naive-bayes-text-classifier

I just started learning Node.js and can't figure out how to load data from a local CSV file and use wink Naive Bayes Text Classifier to learn the data.
I can load the data from local CSV file using this or this example. But the problem is that I do not know how to load wink's Naive Bayes library to client side JS. Is there a way to include node's modules (like wink) in the script that I wrote below?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Naive Bayes</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="./papaparse.min.js"></script>
</head>
<body>
<input type="file" id="csv-file" name="files"/>
</body>
<script>
// REF: https://www.joyofdata.de/blog/parsing-local-csv-file-with-javascript-papa-parse/
// http://archive.is/ySSC8
var data;
function handleFileSelect(evt) {
var file = evt.target.files[0];
Papa.parse(file, {
header: true,
dynamicTyping: true,
complete: function(results) {
data = results;
}
});
}
$(document).ready(function(){
$("#csv-file").change(handleFileSelect);
});
</script>
</html>
An easy way to use node modules when working in the browser is to use browserify. In your working directory:
npm install wink-naive-bayes-text-classifier --save
npm install -g browserify
You'll have to move your code into a separate script file, let us say process-data.js. And, from your HTML you'll be including a different script — bundle.js (we'll come to this at the end):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test Naive Bayes</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<script src="./papaparse.min.js"></script>
</head>
<body>
<input type="file" id="csv-file" name="files"/>
<script src="bundle.js"></script>
</body>
</html>
In your process-data.js, you can now simply require the library as is shown in its documentation.
// REF: https://www.joyofdata.de/blog/parsing-local-csv-file-with-javascript-papa-parse/
// http://archive.is/ySSC8
// Load Naive Bayes Text Classifier
var Classifier = require( 'wink-naive-bayes-text-classifier' );
// Instantiate
var nbc = Classifier();
var data;
function handleFileSelect(evt) {
var file = evt.target.files[0];
Papa.parse(file, {
header: true,
dynamicTyping: true,
complete: function(results) {
data = results;
// You can now use nbc and data :)
// nbc.learn(data[0]);
}
});
}
$(document).ready(function(){
$("#csv-file").change(handleFileSelect);
});
Finally, to create the bundle.js file you'll run browserify:
browserify process-data.js -o bundle.js
This will bundle all the modules you need together into a the file that your HTML is calling. If you don't want to type so much every time you might consider adding an npm script.

How do you run mocha tests in the browser?

Is it just me, or does their documentation not explain how to run the tests in the browser at all?
Do I have to create that HTML file that they show in the example? How do I make it run my specific set of test cases for my project then?
I want the same output as running mocha from project root. All subdirectories inside the test folder need to be included
If we need to run our tests in a browser, we need to set up a simple HTML page to be our test runner page. The page loads Mocha, the testing libraries and our actual test files. To run the tests, we’ll simply open the runner in a browser.
example html code :
<!DOCTYPE html>
<html>
<head>
<title>Mocha Tests</title>
<link rel="stylesheet" href="node_modules/mocha/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script src="node_modules/mocha/mocha.js"></script>
<script src="node_modules/chai/chai.js"></script>
<script>mocha.setup('bdd')</script>
<!-- load code you want to test here -->
<!-- load your test files here -->
<script>
mocha.run();
</script>
</body>
</html>
Setting up a Directory Structure
You should put your tests in a separate directory from your main code files. This makes it easier to structure them, for example if you want to add other types of tests in the future (such as integration tests or functional tests).
The most popular practice with JavaScript code is to have a directory called test/ in your project’s root directory. Then, each test file is placed under test/someModuleTest.js.
Important things :
We load Mocha’s CSS styles to give our test results nice formatting.
We create a div with the ID mocha. This is where the test results are
inserted.
We load Mocha and Chai. They are located in subfolders of the
node_modules folder since we installed them via npm.
By calling mocha.setup, we make Mocha’s testing helpers available.
Then, we load the code we want to test and the test files. We don’t
have anything here just yet.
Last, we call mocha.run to run the tests. Make sure you call this
after loading the source and test files
I thought the documentation wasn't entirely clear too, but I figured it out eventually and got it set up. Here's how:
Include the Mocha script and CSS in Index.html. Also include a div with id "Mocha" for the output to be inserted into. Include the test script you'd like to execute.
<link href="lib/mocha/mocha.css" rel="stylesheet" />
<script src="lib/mocha/mocha.js"></script>
<script src="test/my_mocha_test.js"></script>
<div id="mocha"></div>
In your test file (my_mocha_test.js in this example) include this setup line at the top:
// 'bdd' stands for "behavior driven development"
mocha.setup('bdd');
Now with the test and the Mocha content all loaded, you can run the tests with this command:
mocha.run();
You can add that to an event listener and trigger it on a button push or other event, or you can just run it from the console, but it should put the test output in the div with the "mocha" id. Here's a page with all this set up with code viewable on GitHub for you to
https://captainstack.github.io/public-stackhouse/
My way to do it with:
ES6, import, export, chai
Used mocha 6.1.4 and chai 4.2.0.
src/MyClass.js:
export default class MyClass { }
test/MyClass.js:
import MyClass from "../src/MyClass.js";
let assert = chai.assert;
describe('MyClass tests', function () {
describe('The class', function () {
it('can be instantiated', function () {
assert.isObject(new MyClass());
});
});
});
test/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Mocha</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css">
<script src="mocha.js"></script>
<script src="../node_modules/chai/chai.js"></script>
<script type="module" class="mocha-init">
mocha.setup('bdd');
</script>
<!-- ------------------------------------ -->
<script type="module" src="test.js"></script>
<!-- ------------------------------------ -->
<script type="module">
mocha.run();
</script>
</head>
<body>
<div id="mocha"></div>
</body>
</html>
The mocha.js and mocha.css files were created via mocha init test, but can also be found in node_modules/mocha.
If this is improvable, let me know. The answer is insprired by this post.
Here's the most basic chai/mocha test in the browser.
mocha.setup('bdd');
describe('test', () => {
it('passes', () => {
chai.expect(1).to.eql(1);
});
it('fails', () => {
chai.expect(1).to.eql(2);
});
});
mocha.run();
<div id="mocha" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.0.1/mocha.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai/4.2.0/chai.min.js"></script>

Widget from Angular 2 app webpack

If it is unclear than let's try this again.
In my research I learned that some call it a micro-loader, which is what I am trying to achieve. In the webpack configuration I have this in the plugin section
new HtmlWebpackPlugin({
template: 'src/index.html',
title: METADATA.title,
chunksSortMode: 'dependency',
metadata: METADATA,
inject: 'head'
}),
which turns an html file without any script tags (or even placeholders for them) during compilation in something like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My angular widget</title>
<meta name="description" content="My angular widget">
<!-- base url -->
<base href="/">
<link href="main.23ca1423b5f74b9e7d3a76e9eed69f71.css" rel="stylesheet"><script type="text/javascript" src="polyfills.60dbe827b1b8353af66f.bundle.js" defer></script><script type="text/javascript" src="vendor.0f040ba30b8e909c6a82.bundle.js" defer></script><script type="text/javascript" src="main.d6e9175158901f87b307.bundle.js" defer></script></head>
<body>
<app class="skin-green gbp">
Loading...
</app>
</body>
</html>
It magically adds those 4 files (1 css, 3 js) into the head section.
Now what I want is something like this (the angular-widget.js file)
function loadCss(url) {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = url;
document.getElementsByTagName("head")[0].appendChild(link);
}
loadCss('https://my-domain.com/app/main.1928b5b43a58428e7798d12176de68e3.css');
require(['https://my-domain.com/app/polyfills.60dbe827b1b8353af66f.bundle.js'], function() {
require(['https://my-domain.com/app/vendor.623bbcbf99de3526eab8.bundle.js'], function() {
require(['https://my-domain.com/app/main.d4f6aea1525a044b41da.bundle.js'], function() {
});
});
});
Which is a file I came up which does what I want it to do, but takes manual work everytime and utilizes require.js for now (but can be anything, I don't really care), which is the only point of entry and gets automatically generated during the compilation so I don't have to manually change the hashes everytime something changes and gets redeployed.
-- Old Post starts here
I have an angular 2 project using webpack for compiling. But I do not want the entry point to be the index.html, because the app is to be embeded into another webpage, which I do not have full control over.
I am trying to find a way to output something similar to the index.html but inside a .js file which I than can include on the webpage.
www.some-domain.com/webpage
[...]
<script type="text/javascript" src="https://my-domain.com/angular-widget.js"></script>
<app>
Loading...
</app>
[...]
Is there a way to generate that angular-widget.js during the webpack process? I tried to hijack the HtmlWebpackPlugin, but that expects to output HTML. I am fairly new to the whole webpack process, but my approach right now would be some template where I just can output the different files which are produced by webpack, for example using require.js. But maybe the whole thing is even possible only via webpack?

Require css files with require-css.js in specific order

I have the following structure:
components/
----requirejs
----require-css
----flatUi
--------/css
------------flat.css
menuJSlib/
----js/
--------menu.js
----css/
--------menu.css
samples
----demo/
--------js/
------------main.js
--------css/
------------main.css
--------index.html
I try to load all content stuff in folder menuJSlib with requirejs and require-css in my demo project.
In my index.html in my demo I include requirejs library.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script data-main="js/main" src="../../components/requirejs/require.js"></script>
</body>
</html>
In main.js file in my demo project I have the following code:
require.config({
baseUrl: './../../',
map: {
'*': {
'css': 'components/require-css/css'
}
},
paths: {
GameMenu: 'lib/js/menu',
'layout': 'samples/requirejs_demo/css/main'
}
});
require(['GameMenu', 'css!layout'], function(GameMenu) {
}
And the code in menu.js in my menuJSlib folder is:
define('GameMenu', ['css!components/flat-ui/dist/css/flat-ui.min.css',
'css!lib/css/main.css'], function() {
return GameMenu;
});
How you can see the menu.js have dependencies to css files. Ok all that stuffs works fine, but the problem is that I can find a way to order the css files currectly in this case on dependencies.
As you can see, I try to make order, which get the all depends in menu.js, and next load the main.css in demo folder. In that way main.css in demo will owveride some css rules, which I needed. But the order aways follows:
demo/css/main.css
flatui/css/flat.css
menuJslib/css/main.css
I wont to make this order, without remove the css dependencies in menu.js
flatui/css/flat.css
menuJslib/css/main.css
demo/css/main.css
Is this is posible in that case?

How to run minify files in JavaScript project

I minified my JS file using grunt task runner.
I have a minified file with me but i dont know how to run my project using this minified JS file.
I first 'concat' and then 'uglify'. Now, i don't know how to run.
I am using require and backbone in my Javascript project.
Code: index.html
<!DOCTYPE HTML>
<html>
<head>
<title>Minify POC </title>
</head>
<body>
<script src='main'>
</script>
</body>
</html>
Minified JS file :
/*! Example 10-06-2014 */
var a=10,b=20,c=a+b;console.log("Addition of c ::"+c);
Original file
var a = 10;
var b = 20;
var c = a+ b;
console.log("Addition of c ::"+c);
You need an HTML file to point to the new script. Uglify to a different directory and put a copy of your HTML there, but swap out the script tags...
A usual RequireJS entry point looks like this:
<script data-main="main" src="lib/require.js"></script>
Depending on how your HTML is served, you can add require config to point at the built version. For instance if your HTML is served dynamically, you can add a script block that's included in the page based on environment config:
<script>
var require = {paths: {main: "path/to/built/main.js"}};
</script>
<script data-main="main" src="lib/require.js"></script>
Now, any reference to main will load the built JS, rather than the unbuilt one.

Categories