Skip to content
This repository has been archived by the owner on Nov 16, 2023. It is now read-only.

Add support for dynamic filenames #83

Merged
merged 3 commits into from Dec 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Expand Up @@ -46,8 +46,8 @@ monaco.editor.create(document.getElementById('container'), {

Options can be passed in to `MonacoWebpackPlugin`. They can be used to generate a smaller editor bundle by selecting only certain languages or only certain editor features:

* `output` (`string`) - custom output path for worker scripts, relative to the main webpack `output.path`.
* default value: `''`.
* `filename` (`string`) - custom filename template for worker scripts, respects the same options as [loader-utils' interpolateName](https://github.com/webpack/loader-utils#interpolatename). Useful for adding content-based hashes so that files can be served with long-lived caching headers.
* default value: `'[name].worker.js'`.
* `publicPath` (`string`) - custom public path for worker scripts, overrides the public path from which files generated by this plugin will be served. This wins out over Webpack's dynamic runtime path and can be useful to avoid attempting to load workers cross-origin when using a CDN for other static resources. Use e.g. '/' if you want to load your resources from the current origin..
* default value: `''`.
* `languages` (`string[]`) - include only a subset of the languages supported.
Expand Down
12 changes: 6 additions & 6 deletions index.d.ts
@@ -1,12 +1,6 @@
import { Plugin } from 'webpack'

interface IMonacoEditorWebpackPluginOpts {
/**
* custom output path for worker scripts, relative to the main webpack `output.path`.
* Defaults to ''.
*/
output?: string;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This new option subsumes the old output option since filenames can include directories through use of a slash.


/**
* Include only a subset of the languages supported.
*/
Expand All @@ -18,6 +12,12 @@ interface IMonacoEditorWebpackPluginOpts {
*/
features?: string[];

/**
* Specify a filename template to use for generated files.
* Use e.g. '[name].worker.[contenthash].js' to include content-based hashes.
*/
filename?: string;

/**
* Override the public path from which files generated by this plugin will be served.
* This wins out over Webpack's dynamic runtime path and can be useful to avoid attempting to load workers cross-
Expand Down
36 changes: 25 additions & 11 deletions index.js
@@ -1,5 +1,8 @@
const path = require('path');
const webpack = require('webpack');
const loaderUtils = require('loader-utils');
const fs = require('fs');

const AddWorkerEntryPointPlugin = require('./plugins/AddWorkerEntryPointPlugin');
const INCLUDE_LOADER_PATH = require.resolve('./loaders/include');

Expand All @@ -9,17 +12,28 @@ const EDITOR_MODULE = {
worker: {
id: 'vs/editor/editor',
entry: 'vs/editor/editor.worker',
output: 'editor.worker.js',
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer required as the [name] attribute used to resolve the filename template is based on the entry filename. All generated files have the same names as before unless filename is specified.

fallback: undefined
},
};
const LANGUAGES = require('./languages');
const FEATURES = require('./features');

/**
* Return a resolved path for a given Monaco file.
*/
function resolveMonacoPath(filePath) {
return require.resolve(path.join('monaco-editor/esm', filePath));
}

/**
* Return the interpolated final filename for a worker, respecting the file name template.
*/
function getWorkerFilename(filename, entry) {
return loaderUtils.interpolateName({resourcePath: entry}, filename, {
content: fs.readFileSync(resolveMonacoPath(entry))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using loader-utils so that the full breadth of Webpack filename options is supported. We read the entry file from the file system so that content-based hashes will update based on worker file contents.

});
}

const languagesById = mapValues(LANGUAGES, (language, id) => mixin({ label: id }, language));
const featuresById = mapValues(FEATURES, (feature, key) => mixin({ label: key }, feature))

Expand Down Expand Up @@ -51,20 +65,20 @@ class MonacoWebpackPlugin {
this.options = {
languages: languages.map((id) => languagesById[id]).filter(Boolean),
features: features.map(id => featuresById[id]).filter(Boolean),
output: options.output || '',
publicPath: options.publicPath || ''
filename: options.filename || "[name].worker.js",
publicPath: options.publicPath || '',
};
}

apply(compiler) {
const { languages, features, output, publicPath } = this.options;
const { languages, features, filename, publicPath } = this.options;
const compilationPublicPath = getCompilationPublicPath(compiler);
const modules = [EDITOR_MODULE].concat(languages).concat(features);
const workers = modules.map(
({ label, worker }) => worker && (mixin({ label }, worker))
).filter(Boolean);
const rules = createLoaderRules(languages, features, workers, output, publicPath, compilationPublicPath);
const plugins = createPlugins(workers, output);
const rules = createLoaderRules(languages, features, workers, filename, publicPath, compilationPublicPath);
const plugins = createPlugins(workers, filename);
addCompilerRules(compiler, rules);
addCompilerPlugins(compiler, plugins);
}
Expand All @@ -84,11 +98,11 @@ function getCompilationPublicPath(compiler) {
return compiler.options.output && compiler.options.output.publicPath || '';
}

function createLoaderRules(languages, features, workers, outputPath, pluginPublicPath, compilationPublicPath) {
function createLoaderRules(languages, features, workers, filename, pluginPublicPath, compilationPublicPath) {
if (!languages.length && !features.length) { return []; }
const languagePaths = flatArr(languages.map(({ entry }) => entry).filter(Boolean));
const featurePaths = flatArr(features.map(({ entry }) => entry).filter(Boolean));
const workerPaths = fromPairs(workers.map(({ label, output }) => [label, path.join(outputPath, output)]));
const workerPaths = fromPairs(workers.map(({ label, entry }) => [label, getWorkerFilename(filename, entry)]));
if (workerPaths['typescript']) {
// javascript shares the same worker
workerPaths['javascript'] = workerPaths['typescript'];
Expand Down Expand Up @@ -145,14 +159,14 @@ function createLoaderRules(languages, features, workers, outputPath, pluginPubli
];
}

function createPlugins(workers, outputPath) {
function createPlugins(workers, filename) {
return (
[]
.concat(uniqBy(workers, ({ id }) => id).map(({ id, entry, output }) =>
.concat(uniqBy(workers, ({ id }) => id).map(({ id, entry }) =>
new AddWorkerEntryPointPlugin({
id,
entry: resolveMonacoPath(entry),
filename: path.join(outputPath, output),
filename: getWorkerFilename(filename, entry),
plugins: [
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
],
Expand Down
4 changes: 0 additions & 4 deletions languages.js
Expand Up @@ -39,7 +39,6 @@ module.exports = {
worker: {
id: 'vs/language/css/cssWorker',
entry: 'vs/language/css/css.worker',
output: 'css.worker.js',
fallback: 'vs/language/css/cssWorker',
},
},
Expand Down Expand Up @@ -71,7 +70,6 @@ module.exports = {
worker: {
id: 'vs/language/html/htmlWorker',
entry: 'vs/language/html/html.worker',
output: 'html.worker.js',
fallback: 'vs/language/html/htmlWorker',
},
},
Expand All @@ -92,7 +90,6 @@ module.exports = {
worker: {
id: 'vs/language/json/jsonWorker',
entry: 'vs/language/json/json.worker',
output: 'json.worker.js',
fallback: 'vs/language/json/jsonWorker',
},
},
Expand Down Expand Up @@ -216,7 +213,6 @@ module.exports = {
worker: {
id: 'vs/language/typescript/tsWorker',
entry: 'vs/language/typescript/ts.worker',
output: 'typescript.worker.js',
fallback: 'vs/language/typescript/tsWorker',
},
},
Expand Down