From Fedora Project Wiki

Revision as of 20:21, 6 August 2013 by Patches (talk | contribs) (→‎Compilation/Minification: tweak a little bit; minified JS for web apps is OK)

Overview

JavaScript code may be executed locally (by software such as nodejs or rubygem-execjs), and thus special consideration needs to be taken so it meets the high standards expected from all code in Fedora.

Rationale

Duplication

We have a standard to avoid duplication of system libraries. This applies as much to JavaScript libraries as it does to C, python, Java, and any other programming language. The main concern is security. JavaScript code is not vulnerable to buffer overflows like C but it can be subject to attacks from malicious data that attempts to send the user to alternate web sites, steal their information, or execute code via jsonp requests to an alternate server. Duplicating third party libraries in an application leads to these problems sticking with an application even after the upstream library has fixed the issues. It is therefore prohibited.

There are also some JavaScript libraries which are intended to be used on the local system, not served via a web server to a browser. These libraries clearly have all the standard reasons to avoid duplication.

Licensing

It is common to see third-party applications consuming multiple JavaScript libraries. When all of these libraries are placed together in one directory, there is little information to tell what the relationship is between the files. This leads to problems when incompatible licenses are found. For instance, consider a situation where Foo.js is licensed with Apache Software License-2.0, Bar.js and Baz.js licensed with LGPLv2+, and Qux.js with MIT. We have to then audit the code in Foo.js to determine what symbols are potentially being used in other files, and then audit Bar.js and Baz.js to see if those symbols are being used there.

Having separate packages for each library makes diagnosing these problems much easier.

Naming Guidelines

The name of a JavaScript library package must start with js- then the upstream name. For example: js-jquery.

BuildRequires

To ensure the presence of the necessary RPM macros, all packages that provide JavaScript must have:

BuildRequires:  web-assets-devel

Requires

To ensure the availability of the necessary directories, all packages that provide JavaScript must have:

Requires:  web-assets-filesystem

RPM Macros

Macro Normal Definition Notes
_jsdir %{_datadir}/javascript The directory where JavaScript libraries are stored

Install Location

  • If a JavaScript library can be executed locally or consists purely of JavaScript code, it must be installed into a subdirectory of %{_jsdir}.
  • If a package contains JavaScript code, but is never useful outside the browser (e.g. if it is some sort of HTML user interface library) it may instead install to %{_assetdir}. For more information, see the Web Assets guidelines.
  • If a package contains JavaScript code that is only used as part of a web application, and it is not useful to any other applications whatsoever, it may continue to ship that code along with the application. However, that does not absolve it from complying with the rest of these guidelines.
  • If a package contains JavaScript code that is not useful on the web, but only in locally run software (e.g. Node.js or GNOME shell extensions), it should use the appropriate directory for its runtime, not %{_jsdir}. However, that does not absolve it from complying with the rest of these guidelines.
Huh?
Stuff like jquery-ui will never be used server-side, so splitting the JS and non-JS portions and providing compat symlinks and such seems like an unnecessary amount of work. Hence this exception.

Server Location

JavaScript code is included as part of the general Web Assets framework. Therefore, %{_jsdir} is available on Fedora-provided web servers by default at /_sysassets/javascript/.

For instance, jQuery may be installed in %{_jsdir}/jquery/jquery-min.js, so web applications that need to use it can simply include this HTML tag:

<script type="text/javascript" src="/_sysassets/javascript/jquery/jquery-min.js"></script>

Regardless, web applications may want to make subdirectories of %{_jsdir} available under their own directory via aliases or symlinks for compatibility purposes or to eliminate needless deviation from upstream.

Compilation/Minification

If a JavaScript library typically is shipped as minified or compiled code, it must be compiled or minified as part of the RPM build process. Shipping pre-minified or pre-compiled code is unacceptable in Fedora.

The compiler or minifier used by upstream should be used to compile or minify the code. If the minifier used by upstream is unable to be included in Fedora, an alternative minifier may be used. See this page for a list of known problem areas and suggestions for workarounds.

Huh?
There are compiler/minifiers like the Google Closure compiler that will probably never be acceptable for Fedora due to bundled libraries, etc., so it's not a bad compromise to permit alternative minifiers to be used.

Additionally, the uncompiled/unminified version must be included alongside the compiled/minified version.

Minified JavaScript is not useful for JavaScript run locally, as the entire point of minification is to reduce HTTP transfer times. Therefore, JavaScript not intended for the web (e.g. for Node.js or GNOME Shell extensions) must not be minified.

Static Inclusion of Libraries

A single minified JavaScript file may contain bundled code from other JavaScript libraries. Such libraries may include the source of other libraries without an exception from the FPC, provided the following conditions are met:

  • The bundled library must be shipped as a separate package in Fedora, which also meets these guidelines.
  • The bundled library must use the code from that separate package. It must not bundle its own version of the library.
  • The package must include virtual provides in the form Provides: js-includes(<package name>) for all libraries it statically includes in this fashion. web-assets-devel provides a %js_includes macro that will automatically add the version present in the mock buildroot to the virtual provides. To use it, just add %js_includes <package name> anywhere before %prep in your spec file.
Yuck!
I know, but this is done almost universally. (jQuery bundles sizzle.js, for instance.) If we don't allow this, this whole enterprise is a non-starter. I hope this strikes a decent-enough compromise.

Wrappers for Other Languages or Environments

Sometimes there may exist a simple wrapper from a foreign language (like Ruby via rubygem-execjs or Java via rhino) or server-side JavaScript environment (like Node.js) to a pure JavaScript library. Such packages should delete the bundled library code and instead point to and Require the code provided by the primary Fedora package for that library.

Node.js Modules that contain browser/pure-JS components

Some Node.js modules include parts that can be used in the browser or by other server-side JavaScript engines. Such packages should be shipped as one SRPM that contains two packages:

  • One js-foo package that contains the pure JavaScript portion, following these guidelines.
  • One nodejs-foo package that contains the Node.js module portion, following the Node.js guidelines. This may symlink to the necessary files or directories of the js-foo package.

Other Issues

What about the "customize your own library" thing Toshio mentions in his draft?
Pretty much every library that does this also ships a mega-version that we can use, or otherwise offers some sort of modular system we can take advantage of. I don't think it will turn out to be a major problem in practice.