Giter Club home page Giter Club logo

inject's Introduction

Welcome

Inject (Apache Software License 2.0) is a revolutionary way to manage your dependencies in a Library Agnostic way. Some of its major features include:

  • CommonJS Compliance in the Browser (exports.*)
  • Cross domain retrieval of files (via easyXDM)
  • localStorage (load a module once)
  • Frustratingly Simple

Getting Started With Inject

This page is designed to get you up and running with the latest version of Inject. For greater detail, there is an Advanced Usage section, and a guide to the API.

Download Inject

The latest version of inject is always available via the source repository at http://www.injectjs.com/download/. The most recent version is usually at the top, and inside is the required JS and optional HTML files. Copy them to your own server.

As of 0.4.2, you can also get Inject as a Bower package via bower install inject. Our Bower repository can be found here.

Adding Inject to Your Page

This walkthrough is assuming you're using a directory called js which contains all of your javascript, possibly even this file. It also assumes inside of the js directory is a modules directory which will contain all of your modules. Your directory layout might look like the following:

|-index.html
|-relay.html (optional)
|-js
    |-inject.js
    |-modules
      |-math.js
      |-increment.js
      |-program.js

The location of the modules directory does not need to be under the inject.js file, but it's common practice to group files of similar types together such as JavaScript.

Starting Your JavaScript

To use inject, place the following script tags into the <head> of your document

<script type="text/javascript" src="inject.js"></script>
<script type="text/javascript">
  Inject.setModuleRoot("/js/modules");
  require.run("program");
</script>
  • Inject.setModuleRoot is the location of ALL your JS modules. Based on the directory structure above, they are located in the js/modules directory.
  • require.run executes your main entry point, whatever it may be. Given the above directory structure, it will run the program.js file in your module root (from require.setModuleRoot). The .js is added automatically.

Some Quick Configs

Here's some common configuration options you're going to want for Inject

// Set the "root" where all your modules can be found
// you can use an http:// path or just /path/to/modules like above
Inject.setModuleRoot("path");

// Specify how long files should be in localStorage (in minutes)
// or 0 for never, which is great for development
Inject.setExpires(integerValue);

// configure "cross domain" support. You need to put "relay.swf" and "relay.html"
// on your remote server for this to work
Inject.setModuleRoot("http://example-cdn.com/modules");
Inject.setCrossDomain({
  relayHtml: "http://example-cdn.com/relay.html",
});

Writing Some Modules

When you're ready to write your own modules, have a look at the CommonJS Module Examples to get started.

Building From Source

We have a whole section on building from source. Building From Source has all the juicy details.

Next Steps

From here, you can...

On The Shoulders of Giants

Inject couldn't be as great as it is without these other rockstar libraries:

  • easyXDM: Cross Domain Communication
  • lscache: LocalStorage Cache Provider
  • link.js: dependency extraction (from their src/Library/link.js)
  • GoWithTheFlow.js: simple flow control
  • (and a whole lot of npm related things for development)

inject's People

Contributors

apmadhani avatar chrisamaral avatar eoneill avatar fsimeon avatar gvsboy avatar jakobo avatar jimgskoop avatar jimmyhchan avatar joaostein avatar kate2753 avatar mattpowell 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  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

inject's Issues

module.setExports support

http://wiki.commonjs.org/wiki/Modules/SetExports

Introduce a function on modue called .setExports(obj)

  • if modules.exports contains any members, this should throw an error
  • if module.exports is not defined, obj should be assigned to module.exports and returned

Common case implementation

require("awesomeModule");
// ... code.....
return module.setExports(myObj);

This is a lot cleaner than module.exports = myObj, though backwards compatibility should be maintained.

JS Error

JavaScript Lint
1 error(s), 0 warning(s)
105: SYNTAX ERROR: unterminated character class \
  requireRegex = /require[\s]*\([\s]*(?:"|')([\w\\/\.\:]+?)(?:'|")[\s]*\)/gm;
..................................^

Paper Boy dying on 404's

Get the following node server error when using paper boy for 404 not found errors.
/Users/fsimeon/workspace/jsframe/inject/testserver/server.js:24
log(404, req.url, ip, err);
^
ReferenceError: ip is not defined

Determine jQuery Support

https://github.com/amdjs/amdjs-api/wiki/jQuery-and-AMD

We have opted to "true", which means we should add some awareness of loading multiple jQuery versions. What are everyone's thoughts on how to do this?

  1. simply document the warnings associated with loading multiple jQuery items
  2. modify define to be keenly aware of jQuery
  3. disable jQuery AMD and encourage instead the use of pointcuts
  4. find some way to inject pointcuts onto the define() methodology

4 sounds the cleanest actually from a programming perspective:

require.addDefineRule("jquery", {
  before: function() {},
  after: function() {
    // jQuery.jquery.... this contains the version of jQuery... we just need to map it
    require.register("jquery@"+jQuery.jquery, jQuery);
    require.unregister("jquery");
    jQuery.noConflict();
  }
});

Then, whenever code attempts to define "jquery", it will instead be moved into a properly versioned item.

Signal a module's exports have all been loaded

require.async() doesn't offer functionality to indicate when the modules have been loaded (when those sub modules are loaded) A couple options exist

  1. Require that all exports be written simultaneously in the same pass. This means all exports.* items must be written at the same time. When inject() detects the export object has changed, it assumes the module is ready
  2. add a property module.ready, that when set to true indicates the module is ready
  3. add a method to require such as require.provide() that signals the current module is ready

1 is easily the most commonJS compliant (no modifications) though the wiki http://wiki.commonjs.org/wiki/Module also mentions using a require.install style syntax although that's not in any official draft.

2 and 3 also seem like viable options.

localStorage shim for IE 6/7

lscache does not have support for IE6/7 by default. It does, however, look for globalContext.localStorage. It's possible to emulate a localStorage interface using userdata storage. @mattpowell did some initial research on the issue. Here's the known limitations:

  • userdata is restricted to the same path. To solve this for inject(), we would need a file such as relay.html or a static image file that can be referenced. We can then use an iframe for storing the userdata.
  • Storage is limited at 128kb max
  • On overflowing storage, an error w/ error text (not a constant string... sigh) is thrown. lscache can be modified to check for this exception when it does its cache-overflow checks

IE8 - Error on line 1132 - Expected ';'

I'm getting an error from inject.js on line 1132 when trying to run in_arbys in IE8. Commenting out the "\n//@ sourceURL=" + path; for the runCmd var seems to get things working again.

0.2.0 Documentation Updates

  • Change the cache expiration notes in readme from seconds to minutes
  • Remove notes about IE7 support, as lscache doesn't support it
  • Remove notes about localStorage space management
  • change require.ensure() in docs to reference using an array. Proper signature is require.ensure([modules], callback)
  • remove PersistJS references in readme, licenses, etc
  • remove gh-pages branch and references in the readme

Expiration Times in JSON Object

Currently, there's no way to expire items out of the localStorage system.

  • inject().config() probably needs a expire or cacheLength variable of some kind
  • (new Date()).getTime() should probably be added when a new file is saved
  • on file retrieval, if the file has expired, set it to an empty string? (remove the key completely maybe?)

Should clear() also allow for expiring a single key out of the registry? Not sure the use case for this since that sounds like it could be dicey.

Finish Modules 1.0 Tests

The 1.0 Tests cover the basic implementation. The program runs successfully, the following internal tests should be added

  1. test existence of "require" inside of a module and that it is a function
  2. require() works with a string, throws an error with anything else
  3. require() returns an export (this is already validated by math.js)
  4. require() with invalid module id throws an error
  5. in module, exports{} exists and is an object

console.log(require('./m')) crash in require.ensure block

it works:

require.ensure(['./m'], function(require) {
  var m = require('./m');
  console.log(m);
});

it works:

console.log(require('./m'));

it craches:

require.ensure(['./m'], function(require) {
  console.log(require('./m'));
});

with stacktrace:

Uncaught SyntaxError: Unexpected end of input
extractRequiresinject.js:1031
analyzeFileinject.js:1045
onDownloadCompleteinject.js:940
processCallbacksinject.js:1002
xhr.onreadystatechangeinject.js:1144

./m module is module.exports = 'm';

Build System Improvement to create IE 6/7 Builds

We should look into taking advantage of Google Closure Compiler to create OS specific builds as needed. Some example build flags we'd want to support:

  • --with-ie: add legacy support for IE 6/7. Includes localStorage Shim and JSON Native
  • --without-json: do not include JSON, even if you were going to (for example, already exists from another library or is pre-loaded)
  • --without-xd: do not include the porthole cross domain library

This is an initial list from the inject planning meeting at the tail end of 0.2.1

Asynchronous Module Definition Support (Transport/C)

The AMD specification enables the loading of CommonJS Compliant modules using an asynchronous transport mechanism.

https://github.com/amdjs/amdjs-api/wiki/AMD

The interface is defined as:

define(id?, dependencies?, factory);

With the following criteria:

  • id is optional, and can specify a name of the module ID for lookup such as during later require() calls
  • dependencies is optional, and is an array of modules to load for this item. They should be standard require format, with a preference for http://. We'll likely resolve these like any other module
  • factory is required, and is...
    • a callback that will be executed, the exports object should be mutated in the function body
    • an object, which is assigned to module.exports

no-cache option doesn't seem to work

Per the README, setting require.setExpires("0") should disable client-side caching (e.g. localStorage), but that doesn't seem to work. Also, is it the character "0" or the number zero -- the documentation doesn't clarify.

relative requires support

I'm trying out inject and currently you must require everything starting at the module root. It would be great if you could also do relative requires between files, similar to what you can do in node.

Set "this" to the module object

The current wrapper doesn't constrain "this" to the module object.

I've seen before code that checks:

if (this["exports"]) { ...

The only way that'd be valid is if the context of the anonymous function is set to the module object. This probably isn't a bad idea to help prevent items from leaking out of scope.

Alternate manifest using regexes to drive it

Through conversation with @PeterFrueh, jquery's UI modules are difficult to load. In theory, we should be able to maintain the standard syntax:

$ = require("jQuery");
require("jquery.ui.core");
require("jquery.ui.mouse");
require("jquery.ui.widget");
require("jquery.ui.draggable");
// ... continue using $ normally

The limitations we are facing are best summed up as:

  1. the jQuery UI objects look for jQuery in the global context. Because of require sandboxing, this isn't available by default. We could solve this by using the pointcuts syntax, but that yields issue 2 below
  2. The current syntax doesn't allow for an easy way to package this up. You'd end up with a huge manifest, when really all you need is smarter regex rules

The result of this is a proposal for a new syntax that would deprecate require.manifest in favor of simpler additive rules

require.addRule(regex|string, [weight], {
  path: function() {} | string
  pointcuts: {
    before: function() {},
    after: function() {}
  }
});

Finish Modules 1.1 Tests

The Modules 1.1 Tests need to have the following validation steps added

http://wiki.commonjs.org/wiki/Modules/1.1

  1. in a module, require() is a function
  2. requrie() returns the exports{} of the module (already validated)
  3. require() for an invalid module ID throws an error
  4. require.main property (can this be skipped in QUnit, if not then omit)
  5. require.paths property (can this be skipped, if not then omit)
  6. module contains a variable exports{} which is an object literal
  7. module must have a variable exposed called "module"{}
  8. the "module" variable must have an "id" property set to the module identifier
  9. the "module" variable has a "uri" property which is the URL of retrieval

"require" regexp bug

Regular expression used to search for "require" incorrectly includes "li.require" or similar. Wonder if it also incorrectly picks up "@ require" as used in YUI doc?

Versioning

Do we want to support semver strings in the module definition? Since we don't have NPM in the browser, it could be pretty cool to do something like:

Alternatively, we could just leave it up to the user to define a function for inject().config()'s path variable. However, that path variable also doesn't allow any fallbacks (which it should... separate issue there)

Pointcuts for modules

In inject()'s module.paths, there's no way right now to add additional "wrap" items which would improve library compliance. Ideally, you'd want something like...

inject()..modules({
  "jQuery": {
    path: "path here",
    before: "string placed before include"
    after: "string placed after include"
});

The kind of string that would go after could then do things such as capture items from window.*, call noConflict(), etc

lscache: change expiry routine to loop w/ removal of oldest item

Right now, lscache uses a very sledgehammer approach to removing cache items:

https://github.com/pamelafox/lscache/blob/cc9b787f8a03069d1f52a6b64b225eb6a5bbd45e/lscache.js#L82

The oldest 30 items are chopped off. Since this is supposed to be memcache-like, we should actually expire in smaller chunks until we are satisfying the localStorage limit.

  • Can this be done in a while loop w/ small removal chunks?
  • Can we pre-calculate the size allowed for localstorage to avoid this scenario completely?

Fixes should be done via a fork of https://github.com/pamelafox/lscache and submitted back via pull request

dependency not loading

if Class C requires B which in turn requires A, on a test page where I'm using C, I get an inject error like "A not loaded".

Pointcuts Performance from Regex

I've noticed some massive slowdown with the Pointcuts example. After digging through the code, the root of the issue is in scanning large libraries such as jQuery.

It seems to be rooted in the regex we're using when we scan for requires statements. The .replace + push method is not very effective and puts a lot of stuff into memory.

The proposal in commit 9cd921a addresses this by using a second regex for reducing the text down to blocks that are not the require() statements. Performance on this is much better and brings the pointcuts example on par with the other methods of inclusion.

Feedback is requested before I merge this down. Also, is there a cleaner way than the .replace() method for extracting require() matches?

Examples index.html

Right now, the default is default.html, which isn't representative of what it's testing. We should make...

  1. An index.html page with links to the different examples
  2. Remove all the inter-page links (that will become a pain to maintain)
  3. rename default.html to a real page name
  4. update server.js to reflect the new URL to go to

require.ensure callback excecute multiple times

steps to repro:

  1. setup inject server, be able to see the page from localhost:4000/default.html

  2. in default.html file, add console log code as below

    require.ensure(["foo", "bar"], function(require) {
      var foo = require("foo"),
          bar = require("bar");
      document.getElementById("output-foo").innerHTML = foo.sampleString;
    
      var b = new bar.Bar();
      document.getElementById("output-bar").innerHTML = b.baz();
      console.log(1);
    });
    console.log(2);
    
  3. open fire bug, refresh default.html, console prints 2 1 which is correct. But reload the page again, console prints 1 1 1 2, which run callback function 3 times.

  4. it will fix by itself after clear cache, so bug only happens when load module from local cache.

1337

Inject throws errors on line 1337. Nice.

Finish Module 1.1.1 Tests

The Modules 1.1.1 Tests need to have the following validation steps added

http://wiki.commonjs.org/wiki/Modules/1.1.1

  1. in a module, require() is a function
  2. requrie() returns the exports{} of the module (already validated)
  3. require() for an invalid module ID throws an error
  4. require.main property (can this be skipped in QUnit, if not then omit)
  5. require.paths property (can this be skipped, if not then omit)
  6. module contains a variable exports{} which is an object literal
  7. module must have a variable exposed called "module"{}
  8. the "module" variable must have an "id" property set to the module identifier
  9. the "module" variable has a "uri" property which is the URL of retrieval

Enable inject() and modules.* in executing scope on module include

Right now, when a module is included, only the exports object is made visible. To comply with CommonJS, we'll need to add

  • require() / require.async() (the first probably throws an error, the second is inject() )
  • module.* (we already expose exports, but the top level module object should be visible too)

We'll also need to collect from module.exports at the end. This would allow for the overwriting of exports to return a simple function.

LocalStorage limit reached

It's possible to download too much JS into localStorage (or userdata) and exceed the max # of characters allowed in storage. When the file limit is reached the stuff closest to expiration should probably be removed.

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.