Browse Source

Document the plugin and add the define markers

Steven Silvester 8 years ago
parent
commit
c73fd2a6c4
1 changed files with 89 additions and 36 deletions
  1. 89 36
      jupyterlab/plugin.js

+ 89 - 36
jupyterlab/plugin.js

@@ -5,37 +5,20 @@ var path = require('path');
 
 
 /**
-  TODOs
-  - Add our headers and marker text
-  - Handle the context functions
-  - Handle the other bundles
-  - Create the custom loader
-  - Create a manifest with each module and its dependencies
-  - Handle source maps - preserve the relative original lines of text so we
-    can easily generate a source map for the start of each line
-*/
-
+ * A WebPack plugin that generates custom bundles that use version and
+ * semver-mangled require semantics.
+ */
 function JupyterLabPlugin(options) {
   options = this.options = options || {};
   this.name = options.name || 'jupyter';
 }
 
 
-// Notes
-// We can't replace __webpack_require__ during compilation because
-//  it is hard-coded in several places
-// We have to set the module id directly because it is used verbatim
-// to add the requires and we can't necessarily parse them in context
-// dependencies.
-
-// We can't replace the module ids directly, as it messes with compilation
-// We can replace them in regular modules (ones with a userRequest)
-// Context modules we'll have to assemble ourselves or use a better lookup
-// since they are not clearly delimited
-
-// During the emit phase we create our own mangled stuff
-
-
+/**
+ * Plugin installation, called by WebPack.
+ *
+ * @param compiler - The WebPack compiler object.
+ */
 JupyterLabPlugin.prototype.apply = function(compiler) {
   var pluginName = this.name;
   var publicPath = compiler.options.output.publicPath;
@@ -43,12 +26,19 @@ JupyterLabPlugin.prototype.apply = function(compiler) {
     publicPath += '/';
   }
 
+  // Notes
+  // We use the emit phase because it allows other plugins to act on the
+  // output first.
+  // We can't replace the module ids during compilation, because there are
+  // places in the compilation that assume a numeric id.
   compiler.plugin('emit', function(compilation, callback) {
 
     // Explore each chunk (build output):
     compilation.chunks.forEach(function(chunk) {
 
       var sources = [];
+
+      // A manifest for each module and its dependencies.
       var manifest = {};
 
       // Explore each module within the chunk (built inputs):
@@ -74,9 +64,9 @@ JupyterLabPlugin.prototype.apply = function(compiler) {
         manifest[getDefineName(module)] = deps;
       });
 
-      var code = sources.join(',\n\n');
+      var code = sources.join('\n\n');
 
-      // Insert this list into the Webpack build as a new file asset:
+      // Replace the original chunk file.
       // Use the first file name, because the mangling of the chunk
       // file names are private to WebPack.
       var fileName = chunk.files[0];
@@ -89,6 +79,7 @@ JupyterLabPlugin.prototype.apply = function(compiler) {
         }
       };
 
+      // Create the manifest.
       compilation.assets[fileName + '.manifest'] = {
         source: function() {
           return JSON.stringify(manifest);
@@ -104,7 +95,13 @@ JupyterLabPlugin.prototype.apply = function(compiler) {
 };
 
 
-// From a request - find its package root.
+/**
+ * Find a package root path from a request.
+ *
+ * @param request - The request path.
+ *
+ * @returns The path to the package root.
+ */
 function findRoot(request) {
   var orig = request;
   if (path.extname(request)) {
@@ -130,14 +127,27 @@ function findRoot(request) {
 }
 
 
-// Get the package.json associated with a file.
+/**
+ * Get the package.json associated with a file.
+ *
+ * @param request - The request path.
+ *
+ * @returns The package.json object for the package.
+ */
 function getPackage(request) {
   var rootPath = findRoot(request);
   return require(path.join(rootPath, 'package.json'));
 }
 
 
-// From a Webpack module object - find a version-mangled define name.
+/**
+ * Get the define name for a WebPack module.
+ *
+ * @param module - A parsed WebPack module object.
+ *
+ * @returns A version-mangled define name for the module.
+ *    For example, "foo@1.0.1/lib/bar/baz.js".
+ */
 function getDefineName(module) {
   if (!module.context) {
     return '__ignored__';
@@ -154,7 +164,14 @@ function getDefineName(module) {
 }
 
 
-// From a WebPack module object - find its semver-mangled require name.
+/**
+ * Get the require name for a WebPack module.
+ *
+ * @param module - A parsed WebPack module object.
+ *
+ * @returns A semver-mangled define name for the module.
+ *    For example, "foo@^1.0.0/lib/bar/baz.js".
+ */
 function getRequireName(module) {
   if (!module.context) {
     return '__ignored__';
@@ -185,7 +202,13 @@ function getRequireName(module) {
 }
 
 
-// Create our own mangled context module source.
+/**
+ * Create custom context module source.
+ *
+ * @param module - A parsed WebPack module object.
+ *
+ * @returns The new contents of the context module output.
+ */
 function createContextModule(module) {
   // Modeled after Webpack's ContextModule.js.
   var str;
@@ -231,7 +254,20 @@ function createContextModule(module) {
 }
 
 
-// Parse a module.
+
+/**
+ * Parse a WebPack module to generate a custom version.
+ *
+ * @param compilation - The Webpack compilation object.
+ *
+ * @param module - A parsed WebPack module object.
+ *
+ * @param pluginName - The name of the plugin.
+ *
+ * @param publicPath - The public path of the plugin.
+ *
+ * @returns The new module contents.
+ */
 function parseModule(compilation, module, pluginName, publicPath) {
   var requireName = '__' + pluginName + '_require__';
   var defineName = pluginName + 'Define';
@@ -259,6 +295,8 @@ function parseModule(compilation, module, pluginName, publicPath) {
     }
   // Context modules.
   } else if (module.context) {
+    // Context modules have to be assembled ourselves
+    // because they are not clearly delimited in the text.
     source = createContextModule(module);
     source = source.split('webpackContext').join(pluginName + 'Context');
   }
@@ -272,15 +310,30 @@ function parseModule(compilation, module, pluginName, publicPath) {
   source = source.split('__webpack_require__').join(requireName);
 
   // Create our header with a version-mangled defined name.
-  var header = pluginName + '.define("' + getDefineName(module);
+  var defineName = getDefineName(module);
+  var header = '/** START DEFINE BLOCK for ' + defineName + ' **/\n';
+  header += pluginName + '.define("' + getDefineName(module);
   header += '", function (module, exports, ' + requireName + ') {\n';
+  var footer = '\n})\n/** END DEFINE BLOCK for ' + defineName + '**/';
 
   // Combine code indent.
-  return header + source.split('\n').join('\n\t') + '\n})';
+  return header + source.split('\n').join('\n\t') + footer;
 }
 
 
-// Handle an ensure block.
+/**
+ * Handle an ensure block.
+ *
+ * @param compilation - The Webpack compilation object.
+ *
+ * @param source - The raw module source.
+ *
+ * @param publicPath - The public path of the plugin.
+ *
+ * @param regex - The ensure block regex.
+ *
+ * @returns The new ensure block contents.
+ */
 function handleEnsure(compilation, source, publicPath, regex) {
   while (regex.test(source)) {
     var match = source.match(regex);