Giter VIP home page Giter VIP logo

minify's Introduction

Minify License Build Status NPM version Coverage Status

Minify - a minifier of js, css, html and img files.

To get things done Minify uses this amazing tools:

Install

For Node users:

npm i minify -g

For Deno users:

import {minify} from 'npm:minify';

How to use?

CLI

Usage: minify [options]
Options:
  -h, --help                  display this help and exit
  -v, --version               display version and exit
  --js                        minify javascript
  --css                       minify css
  --html                      minify html
  --auto                      auto detect format

The bash command below creates a code snippet saved as hello.js.

Simply copy + paste the code starting with cat, including the EOT on the last line, and press .

$ cat << EOT > hello.js
const hello = 'world';

for (let i = 0; i < hello.length; i++) {
    console.log(hello[i]);
}
EOT

Use the command minify followed by the path to and name of the js file intended to be minified. This will minify the code and output it to the screen.

$ minify hello.js
var a='world';for(let i=0;i<a.length;i++)console.log(a[i]);

You can capture the output with the following:

$ minify hello.js > hello.min.js

You can pass input using cat:

cat << EOT | bin/minify.js --js
> const hello = 'world';
>
> for (let i = 0; i < hello.length; i++) {
>     console.log(hello[i]);
> }
> EOT
var a='world';for(let i=0;i<a.length;i++)console.log(a[i]);

Minify can be used with async-await and try-to-catch:

import {minify} from 'minify';
import tryToCatch from 'try-to-catch';

const options = {
    html: {
        removeAttributeQuotes: false,
        removeOptionalTags: false,
    },
};

const [error, data] = await tryToCatch(minify, './client.js', options);

if (error)
    return console.error(error.message);

console.log(data);

Options

For cli use these options can be provided in a JSON file named .minify.json like so:

{
    "js": {
        "mangle": true,
        "mangleClassNames": true,
        "removeUnusedVariables": true,
        "removeConsole": false,
        "removeUselessSpread": true
    },
    "img": {
        "maxSize": 4096
    },
    "html": {
        "removeComments": true,
        "removeCommentsFromCDATA": true,
        "removeCDATASectionsFromCDATA": true,
        "collapseWhitespace": true,
        "collapseBooleanAttributes": true,
        "removeAttributeQuotes": true,
        "removeRedundantAttributes": true,
        "useShortDoctype": true,
        "removeEmptyAttributes": true,
        "removeEmptyElements": false,
        "removeOptionalTags": true,
        "removeScriptTypeAttributes": true,
        "removeStyleLinkTypeAttributes": true,
        "minifyJS": true,
        "minifyCSS": true
    },
    "css": {
        "compatibility": "*"
    }
}

Minify walking up parent directories to locate and read it’s configuration file .minify.json.

js

In section related to js you can choose type of minifier:

When you want to pass options to terser, use section with the same name, .minify.json will look this way:

{
    "js": {
        "type": "terser",
        "terser": {
            "mangle": false
        }
    }
}

License

MIT

minify's People

Contributors

aminimalanimal avatar atjn avatar bernimoses avatar brollb avatar caffeinatedbits avatar code-forger avatar coderaiser avatar gabrielmaldi avatar ngdangtu-vn avatar peterdavehello avatar pierrelegagneur avatar stevewhitmore avatar stoshiya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

minify's Issues

example

Is there an example of min.js it creates?

please tag release versions

Hey, thanks for the project. It's exactly what I was looking for. It would be great if you would tag the repo with the version that's in the package.json so there's a notion of what the stable states are.

Improve coverage

Would be great to improve code coverage:

-----------|---------|----------|---------|---------|-------------------
File       | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files  |   94.44 |    73.08 |     100 |   94.44 |
 css.js    |      90 |       80 |     100 |      90 | 27
 html.js   |     100 |      100 |     100 |     100 |
 img.js    |     100 |    66.67 |     100 |     100 | 29
 js.js     |   88.89 |       80 |     100 |   88.89 | 23
 minify.js |   93.94 |       60 |     100 |   93.94 | 32,44
-----------|---------|----------|---------|---------|-------------------

Minification bug when there is "<" without a ">"

If the file contains this example content, the minification does not works:

<p>
   I <3 minify
</p>

If you try to minify a file with this text, the "error" callback argument will gets a "Parse error" with the text of the line 2 (of this example).
The problem is with open tags that does not have a close tag but in html this can happens, as in the example.

Minify version: 1.4.3

Save direct to file

Hi:

Thanks for the package. It's great.

Can you add a third parameter for save the content into a file?

By example:
minify 'file.js' 'file.min.js'

That to create a file 'file.min.js' with the content minified.

Thanks.

Flags for commands

Are there any flags supported by minify, for example minify src/index.html > public/index.html --removeOptionalTags: false

I ask this because I need to set removeOptionalTags to false(because it does not include the ending and ) and minify one file and have the output in another. Your example code only allows for outputting it via the command line which is not helpful.

Code currently:

const minify = require('minify');
const options = {
    html: {
        removeOptionalTags: false
    },
};

minify('public/index.html', options)
    .then(console.log)
    .catch(console.error);

Hope you can help me out!
Also, why are </body> and </html> considered optional?

minify fails when minifying Bootstrap v4/Font Awesome v5 css

Attempting to use minify with Bootstrap v4 or Font Awesome v5 results in an undefined result. The offending styles are listed below.

To reproduce, add each style into a file test.css and run cli command minify test.css. For the Font Awesome styles you'll need to download the Font Awesome npm package and copy the contents of the webfonts folder into the same location as the above test.css file.

// Bootstrap v4 forms break minify
.was-validated .form-control:invalid, .form-control.is-invalid {
  border-color: #dc3545;
  padding-right: calc(1.5em + 0.75rem);
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23dc3545' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23dc3545' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");
  background-repeat: no-repeat;
  background-position: center right calc(0.375em + 0.1875rem);
  background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem); }
// Font Awesome v5 eot breaks minify
@font-face {
  font-family: 'Font Awesome 5 Free';
  font-style: normal;
  font-weight: 900;
  src: url('#./fa-solid-900.eot'); }
// Font Awesome v5 svg breaks minify
@font-face {
  font-family: 'Font Awesome 5 Free';
  font-style: normal;
  font-weight: 900;
  src: url('#./fa-solid-900.svg#fontawesome') format('svg'); }

Error: Cannot find module 'fs/promises'

When I make an fresh installation with minify and do execute it, I get this error:

Error: Cannot find module 'fs/promises'
Require stack:

  • C:\Projects...\node_modules\minify\lib\minify.js
  • C:\Projects...\app\Helpers\File.js
  • C:\Projects...\node_modules\require-stack\src\index.js
  • C:\Projects.....\node_modules\require-stack\index.js
  • C:\Projects.........\node_modules@adonisjs\fold\src\Ioc\index.js
  • C:\Projects,,,......\node_modules@adonisjs\fold\index.js
  • C:\Projects........\server.js

Support reading from STDIN instead of a file

As a Unix user, I want minify to treat the fielname - to mean read from STDIN rather than a file, so that I can pipe data directly to minify without having to save it in a file.

--js flag seems to be broken

Hello,

Since minify v5.2.0, the --js flag seems to no longer work. For example:

$ cat << EOT > hello.js
const hello = 'world';

for (let i = 0; i < hello.length; i++) {
    console.log(hello[i]);
}
EOT
$ cat hello.js | minify --js
Promise { <pending> }

With minify v5.1.1 I get the expected result:

$ cat hello.js | minify --js
const hello="world";for(let l=0;l<hello.length;l++)console.log(hello[l]);

A workaround for minify v5.2.0 and v6.0.0 is to not use the --js flag

$ minify hello.js 
const hello="world";for(let l=0;l<hello.length;l++)console.log(hello[l]);

Cannot find module '..'

Using the following CSS:

@font-face {
font-family: 'Open Sans';
font-weight: normal;
font-style: normal;
src: local('Open Sans'),
local('Open-Sans-regular'),
url('../fonts/OpenSans2/Regular/Open-Sans-regular.woff2') format('woff2'),
url('../fonts/OpenSans2/Regular/Open-Sans-regular.woff') format('woff');
}

From the current working directory, I can access the paths above as they are (including the ".."). However when trying to minify the CSS file, the output is:

Cannot find module '..'

I am using minify v2.1.6, npm v5.0.3 and nodejs v6.11.0.

stream

can we pipe stream to minify ?

HTML minification strips head tag and closing /body and /html tags

Noticed that my HTML templates get a bit mangled unexpectedly where the <head>, and closing </body>, </html> tags get stripped out of the resulting template file.

<!-- ORIGINAL -->
<!DOCTYPE html>
<html lang="en">
<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>Document</title>
    <meta name="application-name" content="APP_NAME_HERE">
    <link rel="stylesheet" href="CDN_CSS_FILE_REFERENCE">
</head>
<body>
    <main id="app" role="main">

    </main>

    <script src="CDN_SCRIPT_FILE_REFERENCE"></script>
    <script src="CDN_SCRIPT_FILE_REFERENCE"></script>
    <script src="CDN_SCRIPT_FILE_REFERENCE"></script>
    <script src="LOCAL_SCRIPT_FILE_REFERENCE"></script>
</body>
</html>
<!-- MINIFIED (expanded for readability) -->
<!DOCTYPE html>
<html lang=en>
<meta charset=utf-8>
<meta http-equiv=x-ua-compatible content="ie=edge">
<meta name=viewport content="width=device-width,initial-scale=1">
<title>Document</title>
<meta name=application-name content=APP_NAME_HERE>
<link rel=stylesheet href=CDN_CSS_FILE_REFERENCE>
<main id=app role=main>
</main>
<script src=CDN_SCRIPT_FILE_REFERENCE></script>
<script src=CDN_SCRIPT_FILE_REFERENCE></script>
<script src=CDN_SCRIPT_FILE_REFERENCE></script>
<script src=LOCAL_SCRIPT_FILE_REFERENCE></script>

Just tested the resulting markup in Chrome (v52) and FireFox (47/48) and it seems to recognize the markup just fine. Never seen this before and was curious if this was intended functionality? as it seems to heavily rely on browsers properly parsing these minimalistic files.

1.4.4 - JS error in css.js

I updated to 1.4.4 and started getting the following error:

TypeError: Cannot read property '0' of undefined
at xxx\node_modules\minify\lib\css.js:32:44
at Function.ExecProto.exec.try (xxx\node_modules\minify\node_modules\execon\lib\exec.js:189:23)
at Object.module.exports as css
at optimizeData (xxx\node_modules\minify\lib\minify.js:29:21)
at onDataRead (xxx\node_modules\minify\lib\minify.js:110:9)
at xxx\node_modules\minify\lib\minify.js:94:17
at fs.js:271:14
at Object.oncomplete (fs.js:107:15)

Upon investigation, it appears in css.js line 31, that the object "min" does not have the referenced "error" property but does have an "errors" property
Altering it to use "min.errors[0]" fixes the error for me.

Error when using stdin

I have this in file.js:

function hello() { 
	if (2 > 3) 
		console.log('for real');
}

I can run minify and pass the filename:

> minify file.js
[ 'function hello(){0}' ]
>

But I can't pass in the content through stdin:

> cat file.js | minify --js
TypeError: minify[name](...).then is not a function
    at processStream (/home/sturm/.nvm/versions/node/v8.11.3/lib/node_modules/minify/bin/minify.js:68:10)
    at Socket.read (/home/sturm/.nvm/versions/node/v8.11.3/lib/node_modules/minify/bin/minify.js:39:9)
    at emitNone (events.js:106:13)
    at Socket.emit (events.js:208:7)
    at emitReadable_ (_stream_readable.js:513:10)
    at emitReadable (_stream_readable.js:507:7)
    at onEofChunk (_stream_readable.js:492:3)
    at readableAddChunk (_stream_readable.js:220:5)
    at Socket.Readable.push (_stream_readable.js:208:10)
    at Pipe.onread (net.js:626:8)
>

Cannot find module 'fs/promises'

I tried googling it it seems that this package is not available in some version of node 12. However I am using node 13.

https://stackoverflow.com/questions/64725249/fs-promises-api-in-typescript-not-compiling-in-javascript-correctly

What is the recommended version of nodejs where this works?

➜  word-highlighter git:(master) ✗ npx minify ./build/build.js > ./build/build.min.js
Cannot find module 'fs/promises'
Require stack:
- /mnt/c/Users/windows/Desktop/word-highlighter/node_modules/minify/lib/minify.js
- /mnt/c/Users/windows/Desktop/word-highlighter/node_modules/minify/bin/minify.js
➜  word-highlighter git:(master) ✗ which node
/home/user/.nvm/versions/node/v13.14.0/bin/node

turn off uglify?

Hi, first off thanks for this lib! Is it possible to turn off uglify when running minify via the command line?

CLI doesn't do anything with html that has inlined css/js

To reproduce:

npm i minify -g
git clone https://github.com/mkgh/mkgh.github.io.git && cd mkgh.github.io
minify index.html.src

Output:

minify: reading file index.html.src...
minify: file index.html.src read
minify: file (sum).src written...
<!DOCTYPE html> 
<html lang="en">
<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>Michael Keating</title>
  <meta name="description" content="Javascript Programmer">

  <style type="text/css" media="screen">
:not(head), :not(head):before, :not(head):after { 
  background: transparent;
  display: block;
  position: relative;
  width: 100%;
  margin: 0;
  padding: 0;
  outline: 0;
  border: 0;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  text-transform: none;
}

html {
  min-width: 256px;
  font: bold 36px/1.3 Helvetica; 
  font-family: "HelveticaNeue-Light", "Helvetica Neue Light", 
    "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}

a {
  width: auto;
  display: inline;
  float: right;
  color: #517038;
  text-decoration: none;
  padding: 0 10px;
}

a:active, a:hover, a:focus {
  color: #619438;
  outline: 0;  
}

body { max-width: 812px; margin: 100px auto 200px; padding: 0 48px; }
header { font-size: 2em; margin-bottom: 64px; } 
header > h1 { font-size: 1em; }

footer {
  margin-bottom: 18px; 
  padding-bottom: 64px;
  border-bottom: .24em dashed black;
}

article > h2 { color: #aaa; padding: 32px 0; }
article > p { color: #ccc; text-align: justify; }

@media (min-width: 641px) and (max-width: 750px) {
  html { font-size: 24px; }
}
@media (min-width: 401px) and (max-width: 640px) {
  html { font-size: 16px; }
}
@media (min-width: 321px) and (max-width: 400px) {
  html { font-size: 12px; }
  body { padding: 0 36px; }
}
@media (max-width: 320px) {
  html { font-size: 8px; }
  body { padding: 0 24px; }
}
  </style>
</head>

<body>
  <header>
    <h1 title="Michael Keating">Michael Keating:</h1>
    <p>I am programming.</p>
  </header>

  <footer>
    <p title="email">smtp
      <a href="mailto:[email protected]">[email protected]</a>
    </p>
    <p title="github">code
      <a href="http://github.com/mkgh/">@mkgh</a>
    </p>
    <p title="twitter">social
      <a href="http://twitter.com/packagejson/">@packagejson</a>
    </p>
  </footer>

  <article>
    <h2>About</h2>
    <p>I'm a node.js web developer from Las Vegas. 
      I believe good-will and communality is utilitarian in nature,
      and totally embrace both into my life-style.
      The unknown excites me, and curiosity drives me.
      I write code because I overthink things.
    </p>
  </article>
</body>

</html>

"Error: fn should be a function!" after latest release

I've installed the latest version (7.2.1) and when I tried to minify a simple .js file I'm getting this error:

Error: fn should be a function!
    at check (...\node_modules\try-to-catch\lib\try-to-catch.js:15:15)
    at module.exports (...\node_modules\try-to-catch\lib\try-to-catch.js:4:5)
    at minify (...\node_modules\minify\bin\minify.js:60:43)

Usage with rollup ?

Hi !
I was wondering if there is an easy integration with rollup ?
Thank's !

Use heredoc sytax to create hello.js in the README.md

The more simple way for creating a hello.js is to use here-doc syntax, and avoid to instruct the user to enter some control+key stuff:

Instead of this:

The bash command below prompts the user to enter a code snippet to be saved in "hello.js".

Press <enter> after the closing } and then either ^D or ^C to finish the prompt.

$ cat > hello.js
const hello = 'world';

for (let i = 0; i < hello.length; i++) {
    console.log(hello[i]);
}
^D

That paragraph could be this:

The bash command below creates a code snippet saved as "hello.js".

Simply copy + paste the code starting with cat, including the EOT on the last line, and press <enter>.

$ cat <<EOT > hello.js
const hello = 'world';

for (let i = 0; i < hello.length; i++) {
    console.log(hello[i]);
}
EOT

CSS comment block is not being removed

I am minifying several CSS files into one. Some files have /** comment blocks **/ and are not being removed as part of the minification. Using Minify v2.0.10.

How to use minify in webpages ?

Hi i want to use minify on client side , so any idea how to do it , i search i found webpacks , browerify , so can you guide me to make package of it so that it can be used on client side

thanks

Error on overwriting file with minified content

I'd like to use this tool in my CD pipeline to overwrite a simple HTML file I have for a site. However, using the same input & output throws an error and does not succeed.

➜  start_page git:(master) ✗ npx minify static/index.html > static/index.html
npx: installed 25 in 2.483s
AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:

  assert(data)

    at AsyncFunction.module.exports [as html] (/home/x/.npm/_npx/48208/lib/node_modules/minify/lib/html.js:38:5)
    at onDataRead (/home/x/.npm/_npx/48208/lib/node_modules/minify/lib/minify.js:75:44)
    at optimize (/home/x/.npm/_npx/48208/lib/node_modules/minify/lib/minify.js:61:18)
    at async minify (/home/x/.npm/_npx/48208/lib/node_modules/minify/lib/minify.js:35:12)
    at async Promise.all (index 0) {
  generatedMessage: true,
  code: 'ERR_ASSERTION',
  actual: '',
  expected: true,
  operator: '=='
}

As this is the very last step in a deploy I really have no need to keep the original, unminified version around, so overwriting is ideal. As of now I have to write, remove the original, and then rename the minified version, which is a bit of an annoyance.

I'll take a look myself, see if I can't get something together to resolve this.

Enhancement: Select the minimum length format for strings

To further shrink JS content, we can select string literal formats tailored to reduce the number of escape characters involved, for each individual string constant. E.g., '"' is preferable to "\"", and "'" is preferable to '\''.

  • For each string constant, compare how the constant would be quote-escaped in double- vs. single-quoted formatted literals.
  • Select the minimal length format for that particular string constant and emit to output.
  • Disregard backticked, interpolated strings from this optimization.

Ask for permission

Hi author!

I would like to change some code in your package and publish as ekit-minify. Would you like to let me do that?

What I have changed are:

  • Disable console.log
  • Public your main.optimize to package root.

Checkout my package: https://npmjs.org/package/ekit-minify

Thanks!

All background:url(...) encoded as base64

Hi Guys

I've been using this package for a few months now in a build script. I'm currently travelling so I had to install it on my crackbook pro. I'm not sure what version I was running at home, as I don't have my pc with me, but it seems everything is importing as base64 encoded uris instead of the relative uri's.

Looking at changes in the past few versions, I would think this is related to clean-css, but I can't seem to see any changes there either.

Is there an option to not encode the images as base64 and just leave them as relatively pathed uri's in my css?

Thanks in advance :)

No output on Windows

Using the latest version (3.0.4) installed globally, the output file is always blank regardless of whether I'm minifying js or css files. I'm using this on the command line, i.e.:

minify scripts.js > script.min.js

Available as a static library file?

I want to use this in my project where node module can't be used. I have an option of including a static library file and get things done using that file.

Any way I can use this library as a static file to simply include in my project?

Sync method

Is it possible to have a sync version?

var minified = minifySync("foo.js");

util.io 0.7.1

util.io 0.7.1 removed "call" method.

Either fix usage or lock dependency on 0.7.0

error at minify.js line 126

fix(output) css file without rules results in '' == true

Using the command line on windows, minifying a css file without any rules (only comments) results in '' == true. I assume the file is interpreted as a javascript file. If so, is there a way to force the type of minification on windows using command line?

To reproduce:

  • file test.css containing: /* dummy comment */
  • command line: minify test.css
  • output: '' == true

No way to pass arguments to uglify-js

I want to pass arguments to uglify and I can't find a way to do it

var uglify_opts = { compress: { dead_code: true } }
minify('file.js', uglify_opts, (e, data) => {
    //... do stuff
}) 

And I'm looking through the source, i don't think they even get passed?

Latest version (3.0.3) fails with syntax error

I didn't notice the major version update from 2.x to 3.x, and now it seems to break on an existing project (using minify v3.0.3):

$ minify file.js
../node_modules/minify/bin/minify.js:9
const log = (...args) => {
             ^^^

SyntaxError: Unexpected token ...
    at exports.runInThisContext (vm.js:53:16)
    at Module._compile (module.js:373:25)
    at Object.Module._extensions..js (module.js:416:10)
    at Module.load (module.js:343:32)
    at Function.Module._load (module.js:300:12)
    at Function.Module.runMain (module.js:441:10)
    at startup (node.js:140:18)
    at node.js:1043:3

I reverted the module to v2.1.8 and that same command works fine.

NodeJS version: v4.8.7

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.