README.md in hanami-assets-1.3.5 vs README.md in hanami-assets-2.1.0.beta2

- old
+ new

@@ -3,12 +3,12 @@ Assets management for Ruby web projects ## Status [![Gem Version](https://badge.fury.io/rb/hanami-assets.svg)](https://badge.fury.io/rb/hanami-assets) -[![CI](https://github.com/hanami/assets/workflows/ci/badge.svg?branch=master)](https://github.com/hanami/assets/actions?query=workflow%3Aci+branch%3Amaster) -[![Test Coverage](https://codecov.io/gh/hanami/assets/branch/master/graph/badge.svg)](https://codecov.io/gh/hanami/assets) +[![CI](https://github.com/hanami/assets/workflows/ci/badge.svg?branch=main)](https://github.com/hanami/assets/actions?query=workflow%3Aci+branch%3Amain) +[![Test Coverage](https://codecov.io/gh/hanami/assets/branch/main/graph/badge.svg)](https://codecov.io/gh/hanami/assets) [![Depfu](https://badges.depfu.com/badges/4b37347bd74042ff96477495cc16531d/overview.svg)](https://depfu.com/github/hanami/assets?project=Bundler) [![Inline Docs](http://inch-ci.org/github/hanami/assets.svg)](http://inch-ci.org/github/hanami/assets) ## Contact @@ -22,18 +22,18 @@ * Forum: https://discuss.hanamirb.org * Chat: http://chat.hanamirb.org ## Rubies -__Hanami::Assets__ supports Ruby (MRI) 2.3+ and JRuby 9.1.5.0+ +__Hanami::Assets__ supports Ruby (MRI) 3.0+ ## Installation Add this line to your application's Gemfile: ```ruby -gem 'hanami-assets' +gem "hanami-assets" ``` And then execute: ```shell @@ -46,30 +46,35 @@ $ gem install hanami-assets ``` ## Usage +### Command Line (CLI) + +During development run `bundle exec hanami server`. +Your app will start the assets management. + ### Helpers -`Hanami::Assets` provides asset-specific helpers to be used in templates. +Hanami Assets provides asset-specific helpers to be used in templates. They resolve one or multiple sources into corresponding HTML tags. Those sources can be either a name of a local asset or an absolute URL. Given the following template: ```erb <!doctype HTML> <html> <head> <title>Assets example</title> - <%= stylesheet 'reset', 'grid', 'main' %> + <%= assets.css "reset", "app" %> </head> <body> <!-- ... --> - <%= javascript 'https://code.jquery.com/jquery-2.1.1.min.js', 'application' %> - <%= javascript 'modals' %> + <%= assets.js "app" %> + <%= assets.js "https://cdn.somethirdparty.script/foo.js", async: true %> </body> </html> ``` It will output this markup: @@ -78,353 +83,149 @@ <!doctype HTML> <html> <head> <title>Assets example</title> <link href="/assets/reset.css" type="text/css" rel="stylesheet"> - <link href="/assets/grid.css" type="text/css" rel="stylesheet"> - <link href="/assets/main.css" type="text/css" rel="stylesheet"> + <link href="/assets/app.css" type="text/css" rel="stylesheet"> </head> <body> <!-- ... --> - <script src="https://code.jquery.com/jquery-2.1.1.min.js" type="text/javascript"></script> - <script src="/assets/application.js" type="text/javascript"></script> - <script src="/assets/modals.js" type="text/javascript"></script> + <script src="/assets/app.js" type="text/javascript"></script> + <script src="https://cdn.somethirdparty.script/foo.js" type="text/javascript" async></script> </body> </html> ``` -Let's have a look at the corresponding Ruby code. -In this example we use ERb, but remember that `Hanami::Assets` is compatible with -all the rendering engines such as HAML, Slim, Mustache, etc.. - -```ruby -require 'erb' -require 'hanami/assets' -require 'hanami/assets/helpers' - -class View - include Hanami::Assets::Helpers - - def initialize - @template = File.read('template.erb') - @engine = ERB.new(@template) - end - - def render - @engine.result(binding) - end -end - -View.new.render # => HTML markup -``` - -For advanced configurations, please have a look at -[`Hanami::Assets::Configuration`](https://github.com/hanami/assets/blob/master/lib/hanami/assets/configuration.rb). - ### Available Helpers This gem ships with the following helpers: - * `javascript` - * `stylesheet` + * `javascript` (aliased as `js`) + * `stylesheet` (aliased as `css`) * `favicon` - * `image` + * `image` (aliased as `img`) * `video` * `audio` - * `asset_path` - * `asset_url` + * `path` -### Development mode +## App Structure -`Hanami::Assets` can help you during the development process of your application. -It can manage multiple source directories for each asset type or run a -preprocessor for you. +Hanami applications are generated via `hanami new` CLI command. -#### Sources +Among other directories, it generates a specific structure for assets: -Imagine to have your application's javascripts under `app/assets/javascripts` and that -those assets depends on a vendored version of jQuery. - -```ruby -require 'hanami/assets' - -Hanami::Assets.configure do - compile true - - sources << [ - 'app/assets', - 'vendor/jquery' - ] -end -``` - -When from a template you do: - -```erb -<%= javascript 'jquery', 'jquery-ui', 'login' %> -``` - -`Hanami::Assets` looks at the defined sources and **lazily copies** those files -under `public/assets` (by default), before the markup is generated. - -Your public directory will have the following structure. - ```shell -% tree public -public/ -└── assets - ├── jquery.js - ├── jquery-ui.js - └── login.js - +$ tree app/assets +├── images +│   └── favicon.ico +├── javascripts +│   └── app.ts +└── stylesheets +    └── app.css ``` -**Please remember that sources are recursively looked up in order of declaration.** +#### Entry Points -If in the example above we had a `jquery.js` under `app/assets/javascripts/**/*.js` -that file would be copied into the public directory instead of the one under -`vendor/jquery`. The reason is because we declared `app/assets/javascripts` first. +Entry Points are the JavaScript files or modules that serve as the starting points of your application. +They define the scope of your bundling process and determine which parts of your code will be included in the final output. +By understanding the dependencies of your entry points, Hanami Assets can create efficient and optimized bundles for your JavaScript or TypeScript applications. -#### Preprocessors +When Hanami Assets encounters an import or require statement for an asset, it process the asset file to the output directory. +This process includes any kind of asset: other JavaScript files, stylesheets, images **referenced from the Entry Point**. -`Hanami::Assets` is able to run assets preprocessors and **lazily compile** them -under `public/assets` (by default), before the markup is generated. +The default entry points are: -Imagine you have `main.css.scss` under `app/assets/stylesheets` and `reset.css` under -`vendor/stylesheets`. + * `app/assets/javascripts/app.ts` + * `slices/[slice-name]/assets/javascripts/app.ts` -**The two extensions are important.** -The first one is mandatory and it's used to understand which asset type we are -handling: `.css` for stylesheets. -The second one is optional and it's for a preprocessor: `.scss` for Sass. +You can specify custom Entry Points, by adding an `app.{js,ts,mjs,mts,tsx,jsx}` file into the assets directory of the app or a slice. -```ruby -require 'sassc' -require 'hanami/assets' +An example is: `app/assets/javascripts/login/app.ts` to define a new Entry Point for a Login page where you want to have a more lightweight bundle. -Hanami::Assets.configure do - compile true +#### Static Assets - sources << [ - 'assets', - 'vendor/assets' - ] -end -``` +Except for `javascripts` and `stylesheets` directories, all the other directories are considered **static**. +Their files will be copied as they are to the destination directory. -And in a template you can use the `stylesheet` helper: +If you have a custom directory `app/assets/fonts`, all the fonts are copied to the destination direcotry. -```erb -<%= stylesheet 'reset', 'main' %> -``` +#### Destination Directory -Your public directory will look like this: +The destination directory is `public/assets`. -```shell -% tree public -public/ -└── assets - ├── reset.css - └── main.css -``` +### Sources -### Preprocessors engines +Hanami Assets works with [Yarn](https://yarnpkg.com/). -`Hanami::Assets` uses [Tilt](https://github.com/rtomayko/tilt) to provide support for the most common preprocessors, such as [Sass](http://sass-lang.com/) (including `sassc-ruby`), [Less](http://lesscss.org/), [ES6](https://babeljs.io/), [JSX](https://jsx.github.io/), [CoffeScript](http://coffeescript.org), [Opal](http://opalrb.com), [Handlebars](http://handlebarsjs.com), [JBuilder](https://github.com/rails/jbuilder). +In order to add/remove a source to your application, you should follow Yarn's dependencies management. -In order to use one or more of them, be sure to add the corresponding gem to your `Gemfile` and require the library. +### Preprocessors -#### EcmaScript 6 +Hanami Assets is able to preprocess any kind of JavaScript and CSS flavor. -We strongly suggest you use [EcmaScript 6](http://es6-features.org/) for your next project. -It isn't fully [supported](https://kangax.github.io/compat-table/es6/) yet by browsers, but it's the future of JavaScript. - -As of today, you need to 'transpile' ES6 code into ES5, which current browsers understand. -The most popular tool for this is [Babel](https://babeljs.io), which we support. - ### Deployment -`Hanami::Assets` ships with an executable (`hanami-assets`), which can be used to precompile assets and make them cacheable by browsers (via checksum suffix). +To process the assets during deployment run `bundle exec hanami assets compile`. -__NOTE__: If you're using `Hanami::Assets` with the full `Hanami` framework, you should use `bundle exec hanami assets precompile` instead of `hanami-assets`. +The destination directory will contain the processed assets with an hashed name. -Let's say we have an application that has a main file that requires the entire codebase (`config/environment.rb`), a gem that brings in Ember.js code, and the following sources: +#### Fingerprint Mode -```shell -% tree . -├── apps -│   ├── admin -│   │   ├── assets -│   │   │   └── js -│   │   │   ├── application.js -│   │   │   └── zepto.js -# ... -│   ├── metrics -│   │   ├── assets -│   │   │   └── javascripts -│   │   │   └── dashboard.js -# ... -│   └── web -│   ├── assets -│   │   ├── images -│   │   │   └── bookshelf.jpg -│   │   └── javascripts -│   │   └── application.js -# ... -│   └── vendor -│   └── assets -│   └── javascripts -│   └── jquery.js -└── config -    └── environment.rb -``` +Asset fingerprinting is a technique that involves adding a unique identifier to the filenames of static assets to ensure cache-busting. +By doing so, you can safely cache and deliver updated versions of assets to client browsers, avoiding the use of outdated cached versions and ensuring a consistent and up-to-date user experience. -In order to deploy, we can run: +During the deployment process, Hanami Assets appends to the file name a unique hash. -```shell -bundle exec hanami-assets --config=config/environment.rb -``` +Example: `app/assets/javascripts/app.ts` -> `public/assets/app-QECGTTYG.js` -It will output: +It creates a `/public/assets.json` to map the original asset name to the fingerprint name. -```shell -tree public -public -├── assets -│   ├── admin -│   │   ├── application-28a6b886de2372ee3922fcaf3f78f2d8.js -│   │   ├── application.js -│   │   ├── ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js -│   │   ├── ember-source-e74117fc6ba74418b2601ffff9eb1568.js -│   │   ├── ember-source.js -│   │   ├── ember.js -│   │   ├── zepto-ca736a378613d484138dec4e69be99b6.js -│   │   └── zepto.js -│   ├── application-d1829dc353b734e3adc24855693b70f9.js -│   ├── application.js -│   ├── bookshelf-237ecbedf745af5a477e380f0232039a.jpg -│   ├── bookshelf.jpg -│   ├── ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js -│   ├── ember-source-e74117fc6ba74418b2601ffff9eb1568.js -│   ├── ember-source.js -│   ├── ember.js -│   ├── jquery-05277a4edea56b7f82a4c1442159e183.js -│   ├── jquery.js -│   └── metrics -│   ├── dashboard-7766a63ececc63a7a629bfb0666e9c62.js -│   ├── dashboard.js -│   ├── ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js -│   ├── ember-source-e74117fc6ba74418b2601ffff9eb1568.js -│   ├── ember-source.js -│   └── ember.js -└── assets.json -``` +The simple usage of the `js` helper, will be automatically mapped for you: -#### Compressors - -Minification is a process that shrinks file size in production, by removing unnecessary spaces and characters. -The goal of this step is to have lighter assets, which will be served faster to browsers. - -Hanami supports JavaScript and stylesheet minifiers. - -Because this framework relies on external gems for minification, this feature is **turned off by default**. - -To use minification, we need to specify which gem we want to use and add it to our `Gemfile`. - -##### JavaScript Compressors - -Hanami can use the following compressors (aka minifiers) for JavaScript. - - * `:builtin` - Ruby based implementation of jsmin. It doesn't require any external gem. - * `:yui` - [YUI Compressor](http://yui.github.io/yuicompressor), it depends on [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and it requires Java 1.4+ - * `:uglifier` - [UglifyJS](http://lisperator.net/uglifyjs), it depends on [`uglifier`](https://rubygems.org/gems/uglifier) gem and it requires Node.js - * `:closure` - [Google Closure Compiler](https://developers.google.com/closure/compiler), it depends on [`closure-compiler`](https://rubygems.org/gems/closure-compiler) gem and it requires Java - -```ruby -Hanami::Assets.configure do - javascript_compressor :uglifier -end -``` - -##### Stylesheet Compressors - -Hanami can use the following compressors (aka minifiers) for stylesheets. - - * `:builtin` - Ruby based compressor. It doesn't require any external gem. It's fast, but not an efficient compressor. - * `:yui` - [YUI Compressor](http://yui.github.io/yuicompressor), it depends on [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and it requires Java 1.4+ - * `:sass` - [Sass](http://sass-lang.com/), it depends on [`sassc`](https://rubygems.org/gems/sassc) gem - -```ruby -Hanami::Assets.configure do - stylesheet_compressor :sass -end -``` - -##### Custom Compressors - -We can specify our own minifiers: - -```ruby -Hanami::Assets.configure do - javascript_compressor MyJavascriptCompressor.new - stylesheet_compressor MyStylesheetCompressor.new -end -``` - -### Fingerprint Mode - -This is a mode that can be activated via configuration and it's suitable for production environments. -When generating files, it adds a string to the end of each file name, which is a [checksum](https://en.wikipedia.org/wiki/Checksum) of its contents. -This lets you leverage caching while still ensuring that clients get the most up-to-date assets (this is known as *cache busting*). - -```ruby -Hanami::Assets.configure do - fingerprint true -end -``` - -Once turned on, it will look at `/public/assets.json`, and helpers such as `javascript` will return a relative URL that includes the fingerprint of the asset. - ```erb -<%= javascript 'application' %> +<%= assets.js "app" %> ``` ```html -<script src="/assets/application-d1829dc353b734e3adc24855693b70f9.js" type="text/javascript"></script> +<script src="/assets/app-QECGTTYG.js" type="text/javascript"></script> ``` -### Subresource Integrity (SRI) Mode +#### Subresource Integrity (SRI) Mode -This is a mode that can be activated via the configuration and it's suitable for production environments. +Subresource Integrity (SRI) is a security mechanism that allows browsers to verify the integrity of external resources by comparing their content against a cryptographic hash. It helps protect against unauthorized modifications to external scripts and enhances the security and trustworthiness of web applications. ```ruby -Hanami::Assets.configure do - subresource_integrity true +module MyApp + class App < Hanami::App + config.assets.subresource_integrity = ["sha-384"] + end end ``` Once turned on, it will look at `/public/assets.json`, and helpers such as `javascript` will include an `integrity` and `crossorigin` attribute. ```erb -<%= javascript 'application' %> +<%= assets.js "app" %> ``` ```html -<script src="/assets/application-d1829dc353b734e3adc24855693b70f9.js" type="text/javascript" integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC" crossorigin="anonymous"></script> +<script src="/assets/app-QECGTTYG.js" type="text/javascript" integrity="sha384-d9ndh67iVrvaACuWjEDJDJlThKvAOdILG011RxYJt1dQynvf4JXNORcUiZ9nO7lP" crossorigin="anonymous"></script> ``` -### CDN Mode +#### Content Delivery Network (CDN) Mode +A Content Delivery Network (CDN) is a globally distributed network of servers strategically located in multiple geographical locations. +CDNs are designed to improve the performance, availability, and scalability of websites and web applications by reducing latency and efficiently delivering content to end users. + A Hanami project can serve assets via a Content Delivery Network (CDN). ```ruby -Hanami::Assets.configure do - scheme 'https' - host '123.cloudfront.net' - port 443 - cdn true +module MyApp + class App < Hanami::App + config.assets.base_url = "https://123.cloudfront.net" + end end ``` From now on, helpers will return the absolute URL for the asset, hosted on the CDN specified. @@ -434,51 +235,30 @@ ```html <script src="https://123.cloudfront.net/assets/application-d1829dc353b734e3adc24855693b70f9.js" type="text/javascript"></script> ``` -## Standalone mode - -If you're using `hanami-assets` without `hanami`, you must explicitly boot the framework with: - -```ruby -Hanami::Assets.configure do - # ... -end.load! +```erb +<%= assets.js "app" %> ``` -or - -```ruby -Hanami::Assets.configure do - # ... -end - -# ... - -Hanami::Assets.load! +```html +<script src="https://123.cloudfront.net/assets/app-QECGTTYG.js" type="text/javascript"></script> ``` -## Third party gems +NOTE: We suggest to use SRI mode when using CDN. -Developers can maintain gems that distribute assets for Hanami. For instance `hanami-ember` or `hanami-jquery`. +## Development -To do this, inside your gem you have tell `Hanami::Assets` where to look for assets: +Install: -```ruby -# lib/hanami/jquery.rb -Hanami::Assets.sources << '/path/to/jquery' -``` + * Node + * NPM -## Running tests - - * Make sure you have one of [ExecJS](https://github.com/rails/execjs) -supported runtime on your machine. - * Java 1.4+ (for YUI Compressor and Google Closure Compiler) - -```sh -bundle exec rake test +```bash +$ npm install +$ bundle exec rake test ``` ## Versioning __Hanami::Assets__ uses [Semantic Versioning 2.0.0](http://semver.org) @@ -491,8 +271,6 @@ 4. Push to the branch (`git push origin my-new-feature`) 5. Create new Pull Request ## Copyright -Copyright © 2014-2021 Luca Guidi – Released under MIT License - -This project was formerly known as Lotus (`lotus-assets`). +Copyright © 2014-2023 Hanami Team – Released under MIT License