Frage

I watched the following Google Apps Office video and learned how you can use browserify to package your JS into one file using the node CommonJS packaging system. I like this idea as it also adds many node libraries ported to the browser and it can handle CoffeeScript.

The one thing the video did not cover was how to make a Chrome App that has more then one view still use browserify in a DRY way. Let me explain. Normally your browserify command takes a series of JS files (designed as modules) and concatenates it into a single JS file with some packaging sugar. This is great of you reference that JS file from say your content page, background page, or popup page. However, if you were to have an app that has both a background page and a popup page would you include the same compiled JS file in each? Would this not cause chrome to load the script twice (in two instances)? If so that seems like a lot of waste interpreting everything only to get the parts you want. Or is the require()/exports modal prevent unnecessary interpretation of modules you may not need for a particular context?

If this is not the best practise how should one package modules in a way that each page gets the needed modules in a dry way without having to repeat yourself or having separate browserify bundles per page? How have others approached this topic?

War es hilfreich?

Lösung

A technique that I've found works well is to create a separate bundle for each context (e.g. background, content, etc.). Here's an example directory structure:

.
├── extension
│   ├── js
│   └── manifest.json
├── lib
│   ├── background
│   │   └── index.js
│   ├── content
│   │   └── index.js
│   └── frame
│       ├── index.js
│       ├── models
│       │   └── ...
│       └── views
│           └── ...
└── package.json

Inside the lib directory, create a folder for each context with index.js as the entry point. This file will bootstrap the application for that particular context, requireing whichever modules and initializing that part of the app.

Then use browserify or watchify to create the bundles in ./extension/js/:

$ browserify ./lib/background/index.js -o ./extension/js/background.js
$ browserify ./lib/content/index.js -o ./extension/js/content.js
$ browserify ./lib/frame/index.js -o ./extension/js/frame.js

If you intend to reuse the same module in, say, background.js and content.js, just require() it in each context and browserify will build the bundles accordingly.

This process can be streamlined by using a Gruntfile.js or custom npm script.

You can try a working example of this approach here.

Andere Tipps

In the case of multiple entry pages and one monolithic JS script the idea would be to encapsulate your JS logic in such a way that your background.html or background script will expose needed functions/objects to the global (read window) context. Then in other entry pages such as options or a popup you use this to get access to the background page's global context:

Application = chrome.extension.getBackgroundPage().myGlobalFunction();

This SO Question offers some insight to the layout and interplay.

That allows you to have one version of the browserify created JS and yet allow it to communicate / execute on other pages of the same extension.

Libraries like Browserify are typically designed to support 'single page web applications'. That is, there's typically only a single HTML file involved in the application (usually public/index.html), which simply serves as an entry point that loads the hard dependencies (such as the concatenated output of browserify). Everything else is managed by Javascript, and whichever front-end framework you opt for (i.e. Backbone, SpineJS, etc).

While a single page web app might contain multiple 'screens' of data, the actual HTML for these pages are typically fragments of html (often using a javascript templating middleware such as Handlebars, Moustache, ECO, etc), loaded via AJAX, and then inserted into the running body of the page. That is - these new page fragments already have access to the javascript previously loaded in this page.

So you are being DRY with a SPA because you only have one page, therefore you aren't repeating yourself with JS imports.

If you're previously used to full-stack web development where a large part of UI is rendered by a server-side language, the idea of a single-page web application can be a bit of a shock. While most SPA tend to have a server-side component, this is typically reduced to a RESTful API providing data endpoints (that the AJAX calls will hit) and persistence.

Under windows 10 I used MKLINK to share my source script(js) and style(css) files across projects

MKLINK /J "D:\Projects\Chrome Extension Projects\myproject\shared" "D:\Projects\Chrome Extension Projects\shared" 
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top