|
@@ -3,7 +3,7 @@
|
|
|
| Distributed under the terms of the Modified BSD License.
|
|
|
|----------------------------------------------------------------------------*/
|
|
|
|
|
|
-var path = require('path');
|
|
|
+var plib = require('path');
|
|
|
var fs = require('fs-extra');
|
|
|
var Handlebars = require('handlebars');
|
|
|
var HtmlWebpackPlugin = require('html-webpack-plugin');
|
|
@@ -21,7 +21,7 @@ var mimeExtensions = jlab.mimeExtensions;
|
|
|
var packageNames = Object.keys(mimeExtensions).concat(Object.keys(extensions));
|
|
|
|
|
|
// Ensure a clear build directory.
|
|
|
-var buildDir = path.resolve(jlab.buildDir);
|
|
|
+var buildDir = plib.resolve(jlab.buildDir);
|
|
|
if (fs.existsSync(buildDir)) {
|
|
|
fs.removeSync(buildDir);
|
|
|
}
|
|
@@ -42,31 +42,31 @@ var data = {
|
|
|
};
|
|
|
var result = template(data);
|
|
|
|
|
|
-fs.writeFileSync(path.join(buildDir, 'index.out.js'), result);
|
|
|
-fs.copySync('./package.json', path.join(buildDir, 'package.json'));
|
|
|
+fs.writeFileSync(plib.join(buildDir, 'index.out.js'), result);
|
|
|
+fs.copySync('./package.json', plib.join(buildDir, 'package.json'));
|
|
|
fs.copySync(
|
|
|
- path.join(jlab.outputDir, 'imports.css'),
|
|
|
- path.join(buildDir, 'imports.css')
|
|
|
+ plib.join(jlab.outputDir, 'imports.css'),
|
|
|
+ plib.join(buildDir, 'imports.css')
|
|
|
);
|
|
|
|
|
|
-// Set up variables for watch mode.
|
|
|
-var localLinked = {};
|
|
|
-var ignoreCache = Object.create(null);
|
|
|
+// Set up variables for the watch mode ignore plugins
|
|
|
+let watched = {};
|
|
|
+let ignoreCache = Object.create(null);
|
|
|
Object.keys(jlab.linkedPackages).forEach(function(name) {
|
|
|
- var localPath = require.resolve(path.join(name, 'package.json'));
|
|
|
- localLinked[name] = path.dirname(localPath);
|
|
|
+ if (name in watched) return;
|
|
|
+ const localPkgPath = require.resolve(plib.join(name, 'package.json'));
|
|
|
+ watched[name] = plib.dirname(localPkgPath);
|
|
|
});
|
|
|
-var ignorePatterns = [/^\.\#/]; // eslint-disable-line
|
|
|
|
|
|
/**
|
|
|
* Sync a local path to a linked package path if they are files and differ.
|
|
|
*/
|
|
|
function maybeSync(localPath, name, rest) {
|
|
|
- var stats = fs.statSync(localPath);
|
|
|
+ const stats = fs.statSync(localPath);
|
|
|
if (!stats.isFile(localPath)) {
|
|
|
return;
|
|
|
}
|
|
|
- var source = fs.realpathSync(path.join(jlab.linkedPackages[name], rest));
|
|
|
+ const source = fs.realpathSync(plib.join(jlab.linkedPackages[name], rest));
|
|
|
if (source === fs.realpathSync(localPath)) {
|
|
|
return;
|
|
|
}
|
|
@@ -83,31 +83,148 @@ function maybeSync(localPath, name, rest) {
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * A WebPack Plugin that copies the assets to the static directory and
|
|
|
- * fixes the output of the HTMLWebpackPlugin
|
|
|
+ * A filter function set up to exclude all files that are not
|
|
|
+ * in a package contained by the Jupyterlab repo
|
|
|
*/
|
|
|
-function JupyterFrontEndPlugin() {}
|
|
|
-
|
|
|
-JupyterFrontEndPlugin.prototype.apply = function(compiler) {
|
|
|
- compiler.hooks.afterEmit.tap(
|
|
|
- 'JupyterFrontEndPlugin',
|
|
|
- function() {
|
|
|
- // Copy the static assets.
|
|
|
- var staticDir = jlab.staticDir;
|
|
|
- if (!staticDir) {
|
|
|
+function ignored(path) {
|
|
|
+ path = plib.resolve(path);
|
|
|
+ if (path in ignoreCache) {
|
|
|
+ // Bail if already found.
|
|
|
+ return ignoreCache[path];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Limit the watched files to those in our local linked package dirs.
|
|
|
+ let ignore = true;
|
|
|
+ Object.keys(watched).some(name => {
|
|
|
+ const rootPath = watched[name];
|
|
|
+ const contained = path.indexOf(rootPath + plib.sep) !== -1;
|
|
|
+ if (path !== rootPath && !contained) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const rest = path.slice(rootPath.length);
|
|
|
+ if (rest.indexOf('node_modules') === -1) {
|
|
|
+ ignore = false;
|
|
|
+ maybeSync(path, name, rest);
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ ignoreCache[path] = ignore;
|
|
|
+ return ignore;
|
|
|
+}
|
|
|
+
|
|
|
+// custom webpack plugin definitions.
|
|
|
+// These can be removed the next time @jupyterlab/buildutils is published on npm
|
|
|
+class FrontEndPlugin {
|
|
|
+ constructor(buildDir, staticDir) {
|
|
|
+ this.buildDir = buildDir;
|
|
|
+ this.staticDir = staticDir;
|
|
|
+
|
|
|
+ this._first = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ apply(compiler) {
|
|
|
+ compiler.hooks.afterEmit.tap('JupyterFrontEndPlugin', () => {
|
|
|
+ // bail if no staticDir
|
|
|
+ if (!this.staticDir) {
|
|
|
return;
|
|
|
}
|
|
|
- // Ensure a clean static directory on the first emit.
|
|
|
- if (this._first && fs.existsSync(staticDir)) {
|
|
|
- fs.removeSync(staticDir);
|
|
|
+
|
|
|
+ // ensure a clean static directory on the first emit
|
|
|
+ if (this._first && fs.existsSync(this.staticDir)) {
|
|
|
+ fs.removeSync(this.staticDir);
|
|
|
}
|
|
|
this._first = false;
|
|
|
- fs.copySync(buildDir, staticDir);
|
|
|
- }.bind(this)
|
|
|
- );
|
|
|
-};
|
|
|
|
|
|
-JupyterFrontEndPlugin.prototype._first = true;
|
|
|
+ fs.copySync(this.buildDir, this.staticDir);
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class FilterIgnoringWatchFileSystem {
|
|
|
+ constructor(wfs, ignored) {
|
|
|
+ this.wfs = wfs;
|
|
|
+ // ignored should be a callback function that filters the build files
|
|
|
+ this.ignored = ignored;
|
|
|
+ }
|
|
|
+
|
|
|
+ watch(files, dirs, missing, startTime, options, callback, callbackUndelayed) {
|
|
|
+ const notIgnored = path => !this.ignored(path);
|
|
|
+
|
|
|
+ const ignoredFiles = files.filter(ignored);
|
|
|
+ const ignoredDirs = dirs.filter(ignored);
|
|
|
+
|
|
|
+ const watcher = this.wfs.watch(
|
|
|
+ files.filter(notIgnored),
|
|
|
+ dirs.filter(notIgnored),
|
|
|
+ missing,
|
|
|
+ startTime,
|
|
|
+ options,
|
|
|
+ (
|
|
|
+ err,
|
|
|
+ filesModified,
|
|
|
+ dirsModified,
|
|
|
+ missingModified,
|
|
|
+ fileTimestamps,
|
|
|
+ dirTimestamps,
|
|
|
+ removedFiles
|
|
|
+ ) => {
|
|
|
+ if (err) return callback(err);
|
|
|
+ for (const path of ignoredFiles) {
|
|
|
+ fileTimestamps.set(path, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const path of ignoredDirs) {
|
|
|
+ dirTimestamps.set(path, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ callback(
|
|
|
+ err,
|
|
|
+ filesModified,
|
|
|
+ dirsModified,
|
|
|
+ missingModified,
|
|
|
+ fileTimestamps,
|
|
|
+ dirTimestamps,
|
|
|
+ removedFiles
|
|
|
+ );
|
|
|
+ },
|
|
|
+ callbackUndelayed
|
|
|
+ );
|
|
|
+
|
|
|
+ return {
|
|
|
+ close: () => watcher.close(),
|
|
|
+ pause: () => watcher.pause(),
|
|
|
+ getContextTimestamps: () => {
|
|
|
+ const dirTimestamps = watcher.getContextTimestamps();
|
|
|
+ for (const path of ignoredDirs) {
|
|
|
+ dirTimestamps.set(path, 1);
|
|
|
+ }
|
|
|
+ return dirTimestamps;
|
|
|
+ },
|
|
|
+ getFileTimestamps: () => {
|
|
|
+ const fileTimestamps = watcher.getFileTimestamps();
|
|
|
+ for (const path of ignoredFiles) {
|
|
|
+ fileTimestamps.set(path, 1);
|
|
|
+ }
|
|
|
+ return fileTimestamps;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class FilterWatchIgnorePlugin {
|
|
|
+ constructor(ignored) {
|
|
|
+ this.ignored = ignored;
|
|
|
+ }
|
|
|
+
|
|
|
+ apply(compiler) {
|
|
|
+ compiler.hooks.afterEnvironment.tap('FilterWatchIgnorePlugin', () => {
|
|
|
+ compiler.watchFileSystem = new FilterIgnoringWatchFileSystem(
|
|
|
+ compiler.watchFileSystem,
|
|
|
+ this.ignored
|
|
|
+ );
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
const plugins = [
|
|
|
new DuplicatePackageCheckerPlugin({
|
|
@@ -121,11 +238,15 @@ const plugins = [
|
|
|
}),
|
|
|
new HtmlWebpackPlugin({
|
|
|
chunksSortMode: 'none',
|
|
|
- template: path.join('templates', 'template.html'),
|
|
|
+ template: plib.join('templates', 'template.html'),
|
|
|
title: jlab.name || 'JupyterLab'
|
|
|
}),
|
|
|
new webpack.HashedModuleIdsPlugin(),
|
|
|
- new JupyterFrontEndPlugin({})
|
|
|
+
|
|
|
+ // custom plugin for ignoring files during a `--watch` build
|
|
|
+ new FilterWatchIgnorePlugin(ignored),
|
|
|
+ // custom plugin that copies the assets to the static directory
|
|
|
+ new FrontEndPlugin(buildDir, jlab.staticDir)
|
|
|
];
|
|
|
|
|
|
if (process.argv.includes('--analyze')) {
|
|
@@ -136,10 +257,10 @@ module.exports = [
|
|
|
{
|
|
|
mode: 'development',
|
|
|
entry: {
|
|
|
- main: ['whatwg-fetch', path.resolve(buildDir, 'index.out.js')]
|
|
|
+ main: ['whatwg-fetch', plib.resolve(buildDir, 'index.out.js')]
|
|
|
},
|
|
|
output: {
|
|
|
- path: path.resolve(buildDir),
|
|
|
+ path: plib.resolve(buildDir),
|
|
|
publicPath: '{{page_config.fullStaticUrl}}/',
|
|
|
filename: '[name].[chunkhash].js'
|
|
|
},
|
|
@@ -186,47 +307,13 @@ module.exports = [
|
|
|
]
|
|
|
},
|
|
|
watchOptions: {
|
|
|
- ignored: function(localPath) {
|
|
|
- localPath = path.resolve(localPath);
|
|
|
- if (localPath in ignoreCache) {
|
|
|
- return ignoreCache[localPath];
|
|
|
- }
|
|
|
-
|
|
|
- // Ignore files with certain patterns
|
|
|
- var baseName = localPath.replace(/^.*[\\\/]/, ''); // eslint-disable-line
|
|
|
- if (
|
|
|
- ignorePatterns.some(function(rexp) {
|
|
|
- return baseName.match(rexp);
|
|
|
- })
|
|
|
- ) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- // Limit the watched files to those in our local linked package dirs.
|
|
|
- var ignore = true;
|
|
|
- Object.keys(localLinked).some(function(name) {
|
|
|
- // Bail if already found.
|
|
|
- var rootPath = localLinked[name];
|
|
|
- var contained = localPath.indexOf(rootPath + path.sep) !== -1;
|
|
|
- if (localPath !== rootPath && !contained) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- var rest = localPath.slice(rootPath.length);
|
|
|
- if (rest.indexOf('node_modules') === -1) {
|
|
|
- ignore = false;
|
|
|
- maybeSync(localPath, name, rest);
|
|
|
- }
|
|
|
- return true;
|
|
|
- });
|
|
|
- ignoreCache[localPath] = ignore;
|
|
|
- return ignore;
|
|
|
- }
|
|
|
+ poll: 333
|
|
|
},
|
|
|
node: {
|
|
|
fs: 'empty'
|
|
|
},
|
|
|
bail: true,
|
|
|
- devtool: 'source-map',
|
|
|
+ devtool: 'inline-source-map',
|
|
|
externals: ['node-fetch', 'ws'],
|
|
|
plugins,
|
|
|
stats: {
|