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 2 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
6 changes: 3 additions & 3 deletions README.md
Expand Up @@ -46,11 +46,11 @@ 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'`.
* `languages` (`string[]`) - include only a subset of the languages supported.
* default value: `['apex', 'azcli', 'bat', 'clojure', 'coffee', 'cpp', 'csharp', 'csp', 'css', 'dockerfile', 'fsharp', 'go', 'handlebars', 'html', 'ini', 'java', 'javascript', 'json', 'less', 'lua', 'markdown', 'msdax', 'mysql', 'objective', 'perl', 'pgsql', 'php', 'postiats', 'powerquery', 'powershell', 'pug', 'python', 'r', 'razor', 'redis', 'redshift', 'ruby', 'rust', 'sb', 'scheme', 'scss', 'shell', 'solidity', 'sql', 'st', 'swift', 'typescript', 'vb', 'xml', 'yaml']`.

Some languages share the same web worker. If one of the following languages is included, you must also include the language responsible for instantiating their shared worker:

| Language | Instantiator |
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 @@ -17,6 +11,12 @@ interface IMonacoEditorWebpackPluginOpts {
* Use e.g. '!contextmenu' to exclude a certain feature.
*/
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;
}

declare class MonacoEditorWebpackPlugin extends Plugin {
Expand Down
35 changes: 24 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,18 +12,29 @@ 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
},
alias: 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 = fromPairs(
flatMap(toPairs(LANGUAGES), ([id, language]) =>
[id].concat(language.alias || []).map((label) => [label, mixin({ label }, language)])
Expand Down Expand Up @@ -53,23 +67,22 @@ class MonacoWebpackPlugin {
constructor(options = {}) {
const languages = options.languages || Object.keys(languagesById);
const features = getFeaturesIds(options.features || [], featuresById);
const output = options.output || '';
this.options = {
languages: languages.map((id) => languagesById[id]).filter(Boolean),
features: features.map(id => featuresById[id]).filter(Boolean),
output,
filename: options.filename || "[name].worker.js"
};
}

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

function createLoaderRules(languages, features, workers, outputPath, publicPath) {
function createLoaderRules(languages, features, workers, publicPath, filename) {
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 @@ -140,14 +153,14 @@ function createLoaderRules(languages, features, workers, outputPath, publicPath)
];
}

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 @@ -47,7 +47,6 @@ module.exports = {
worker: {
id: 'vs/language/css/cssWorker',
entry: 'vs/language/css/css.worker',
output: 'css.worker.js',
fallback: 'vs/language/css/cssWorker',
},
alias: undefined,
Expand Down Expand Up @@ -80,7 +79,6 @@ module.exports = {
worker: {
id: 'vs/language/html/htmlWorker',
entry: 'vs/language/html/html.worker',
output: 'html.worker.js',
fallback: 'vs/language/html/htmlWorker',
},
alias: undefined,
Expand All @@ -105,7 +103,6 @@ module.exports = {
worker: {
id: 'vs/language/json/jsonWorker',
entry: 'vs/language/json/json.worker',
output: 'json.worker.js',
fallback: 'vs/language/json/jsonWorker',
},
alias: undefined,
Expand Down Expand Up @@ -258,7 +255,6 @@ module.exports = {
worker: {
id: 'vs/language/typescript/tsWorker',
entry: 'vs/language/typescript/ts.worker',
output: 'typescript.worker.js',
fallback: 'vs/language/typescript/tsWorker',
},
alias: undefined,
Expand Down