Convert to TypeScript
parent
e032f77fb9
commit
0bd24b523b
@ -1,3 +1,4 @@
|
|||||||
/node_modules/
|
/node_modules/
|
||||||
/test/node_modules/
|
/test/node_modules/
|
||||||
/test/dist/*.js
|
/test/dist/*.js
|
||||||
|
/out/
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
/src/
|
||||||
/test/
|
/test/
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.trimTrailingWhitespace": true,
|
||||||
|
"files.insertFinalNewline": true,
|
||||||
|
"editor.tabSize": 2,
|
||||||
|
"editor.insertSpaces": true
|
||||||
|
}
|
@ -1,34 +0,0 @@
|
|||||||
import { Plugin } from 'webpack'
|
|
||||||
|
|
||||||
interface IMonacoEditorWebpackPluginOpts {
|
|
||||||
/**
|
|
||||||
* Include only a subset of the languages supported.
|
|
||||||
*/
|
|
||||||
languages?: string[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Include only a subset of the editor features.
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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-
|
|
||||||
* origin when using a CDN for other static resources.
|
|
||||||
* Use e.g. '/' if you want to load your resources from the current origin.
|
|
||||||
*/
|
|
||||||
publicPath?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare class MonacoEditorWebpackPlugin extends Plugin {
|
|
||||||
constructor(opts?: IMonacoEditorWebpackPluginOpts)
|
|
||||||
}
|
|
||||||
|
|
||||||
export = MonacoEditorWebpackPlugin
|
|
@ -1,218 +0,0 @@
|
|||||||
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');
|
|
||||||
|
|
||||||
const EDITOR_MODULE = {
|
|
||||||
label: 'editorWorkerService',
|
|
||||||
entry: undefined,
|
|
||||||
worker: {
|
|
||||||
id: 'vs/editor/editor',
|
|
||||||
entry: 'vs/editor/editor.worker',
|
|
||||||
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))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const languagesById = mapValues(LANGUAGES, (language, id) => mixin({ label: id }, language));
|
|
||||||
const featuresById = mapValues(FEATURES, (feature, key) => mixin({ label: key }, feature))
|
|
||||||
|
|
||||||
function getFeaturesIds(userFeatures, predefinedFeaturesById) {
|
|
||||||
function notContainedIn(arr) {
|
|
||||||
return (element) => arr.indexOf(element) === -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let featuresIds;
|
|
||||||
|
|
||||||
if (userFeatures.length) {
|
|
||||||
const excludedFeatures = userFeatures.filter(f => f[0] === '!').map(f => f.slice(1));
|
|
||||||
if (excludedFeatures.length) {
|
|
||||||
featuresIds = Object.keys(predefinedFeaturesById).filter(notContainedIn(excludedFeatures))
|
|
||||||
} else {
|
|
||||||
featuresIds = userFeatures;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
featuresIds = Object.keys(predefinedFeaturesById);
|
|
||||||
}
|
|
||||||
|
|
||||||
return featuresIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MonacoWebpackPlugin {
|
|
||||||
constructor(options = {}) {
|
|
||||||
const languages = options.languages || Object.keys(languagesById);
|
|
||||||
const features = getFeaturesIds(options.features || [], featuresById);
|
|
||||||
this.options = {
|
|
||||||
languages: languages.map((id) => languagesById[id]).filter(Boolean),
|
|
||||||
features: features.map(id => featuresById[id]).filter(Boolean),
|
|
||||||
filename: options.filename || "[name].worker.js",
|
|
||||||
publicPath: options.publicPath || '',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(compiler) {
|
|
||||||
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, filename, publicPath, compilationPublicPath);
|
|
||||||
const plugins = createPlugins(workers, filename);
|
|
||||||
addCompilerRules(compiler, rules);
|
|
||||||
addCompilerPlugins(compiler, plugins);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCompilerRules(compiler, rules) {
|
|
||||||
const compilerOptions = compiler.options;
|
|
||||||
const moduleOptions = compilerOptions.module || (compilerOptions.module = {});
|
|
||||||
moduleOptions.rules = (moduleOptions.rules || []).concat(rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
function addCompilerPlugins(compiler, plugins) {
|
|
||||||
plugins.forEach((plugin) => plugin.apply(compiler));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCompilationPublicPath(compiler) {
|
|
||||||
return compiler.options.output && compiler.options.output.publicPath || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
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, entry }) => [label, getWorkerFilename(filename, entry)]));
|
|
||||||
if (workerPaths['typescript']) {
|
|
||||||
// javascript shares the same worker
|
|
||||||
workerPaths['javascript'] = workerPaths['typescript'];
|
|
||||||
}
|
|
||||||
if (workerPaths['css']) {
|
|
||||||
// scss and less share the same worker
|
|
||||||
workerPaths['less'] = workerPaths['css'];
|
|
||||||
workerPaths['scss'] = workerPaths['css'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (workerPaths['html']) {
|
|
||||||
// handlebars, razor and html share the same worker
|
|
||||||
workerPaths['handlebars'] = workerPaths['html'];
|
|
||||||
workerPaths['razor'] = workerPaths['html'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the public path from which to load worker JS files. In order of precedence:
|
|
||||||
// 1. Plugin-specific public path.
|
|
||||||
// 2. Dynamic runtime public path.
|
|
||||||
// 3. Compilation public path.
|
|
||||||
const pathPrefix = Boolean(pluginPublicPath)
|
|
||||||
? JSON.stringify(pluginPublicPath)
|
|
||||||
: `typeof __webpack_public_path__ === 'string' ` +
|
|
||||||
`? __webpack_public_path__ ` +
|
|
||||||
`: ${JSON.stringify(compilationPublicPath)}`
|
|
||||||
|
|
||||||
const globals = {
|
|
||||||
'MonacoEnvironment': `(function (paths) {
|
|
||||||
function stripTrailingSlash(str) {
|
|
||||||
return str.replace(/\\/$/, '');
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
getWorkerUrl: function (moduleId, label) {
|
|
||||||
var pathPrefix = ${pathPrefix};
|
|
||||||
return (pathPrefix ? stripTrailingSlash(pathPrefix) + '/' : '') + paths[label];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})(${JSON.stringify(workerPaths, null, 2)})`,
|
|
||||||
};
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
test: /monaco-editor[/\\]esm[/\\]vs[/\\]editor[/\\]editor.(api|main).js/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: INCLUDE_LOADER_PATH,
|
|
||||||
options: {
|
|
||||||
globals,
|
|
||||||
pre: featurePaths.map((importPath) => resolveMonacoPath(importPath)),
|
|
||||||
post: languagePaths.map((importPath) => resolveMonacoPath(importPath)),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createPlugins(workers, filename) {
|
|
||||||
return (
|
|
||||||
[]
|
|
||||||
.concat(uniqBy(workers, ({ id }) => id).map(({ id, entry }) =>
|
|
||||||
new AddWorkerEntryPointPlugin({
|
|
||||||
id,
|
|
||||||
entry: resolveMonacoPath(entry),
|
|
||||||
filename: getWorkerFilename(filename, entry),
|
|
||||||
plugins: [
|
|
||||||
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function flatArr(items) {
|
|
||||||
return items.reduce((acc, item) => {
|
|
||||||
if (Array.isArray(item)) {
|
|
||||||
return [].concat(acc).concat(item);
|
|
||||||
}
|
|
||||||
return [].concat(acc).concat([item]);
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fromPairs(values) {
|
|
||||||
return values.reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), {});
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapValues(object, iteratee) {
|
|
||||||
return Object.keys(object).reduce(
|
|
||||||
(acc, key) => Object.assign(acc, { [key]: iteratee(object[key], key) }),
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function uniqBy(items, iteratee) {
|
|
||||||
const keys = {};
|
|
||||||
return items.reduce((acc, item) => {
|
|
||||||
const key = iteratee(item);
|
|
||||||
if (key in keys) { return acc; }
|
|
||||||
keys[key] = true;
|
|
||||||
acc.push(item);
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mixin(dest, src) {
|
|
||||||
for (let prop in src) {
|
|
||||||
if (Object.hasOwnProperty.call(src, prop)) {
|
|
||||||
dest[prop] = src[prop];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = MonacoWebpackPlugin;
|
|
File diff suppressed because it is too large
Load Diff
@ -1,128 +1,174 @@
|
|||||||
module.exports = {
|
import { IFeatureDefinition } from "./types";
|
||||||
accessibilityHelp: {
|
|
||||||
|
const featuresArr: IFeatureDefinition[] = [
|
||||||
|
{
|
||||||
|
label: 'accessibilityHelp',
|
||||||
entry: 'vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp',
|
entry: 'vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp',
|
||||||
},
|
},
|
||||||
bracketMatching: {
|
{
|
||||||
|
label: 'bracketMatching',
|
||||||
entry: 'vs/editor/contrib/bracketMatching/bracketMatching',
|
entry: 'vs/editor/contrib/bracketMatching/bracketMatching',
|
||||||
},
|
},
|
||||||
caretOperations: {
|
{
|
||||||
|
label: 'caretOperations',
|
||||||
entry: 'vs/editor/contrib/caretOperations/caretOperations',
|
entry: 'vs/editor/contrib/caretOperations/caretOperations',
|
||||||
},
|
},
|
||||||
clipboard: {
|
{
|
||||||
|
label: 'clipboard',
|
||||||
entry: 'vs/editor/contrib/clipboard/clipboard',
|
entry: 'vs/editor/contrib/clipboard/clipboard',
|
||||||
},
|
},
|
||||||
codeAction: {
|
{
|
||||||
|
label: 'codeAction',
|
||||||
entry: 'vs/editor/contrib/codeAction/codeActionContributions',
|
entry: 'vs/editor/contrib/codeAction/codeActionContributions',
|
||||||
},
|
},
|
||||||
codelens: {
|
{
|
||||||
|
label: 'codelens',
|
||||||
entry: 'vs/editor/contrib/codelens/codelensController',
|
entry: 'vs/editor/contrib/codelens/codelensController',
|
||||||
},
|
},
|
||||||
colorDetector: {
|
{
|
||||||
|
label: 'colorDetector',
|
||||||
entry: 'vs/editor/contrib/colorPicker/colorDetector',
|
entry: 'vs/editor/contrib/colorPicker/colorDetector',
|
||||||
},
|
},
|
||||||
comment: {
|
{
|
||||||
|
label: 'comment',
|
||||||
entry: 'vs/editor/contrib/comment/comment',
|
entry: 'vs/editor/contrib/comment/comment',
|
||||||
},
|
},
|
||||||
contextmenu: {
|
{
|
||||||
|
label: 'contextmenu',
|
||||||
entry: 'vs/editor/contrib/contextmenu/contextmenu',
|
entry: 'vs/editor/contrib/contextmenu/contextmenu',
|
||||||
},
|
},
|
||||||
coreCommands: {
|
{
|
||||||
|
label: 'coreCommands',
|
||||||
entry: 'vs/editor/browser/controller/coreCommands',
|
entry: 'vs/editor/browser/controller/coreCommands',
|
||||||
},
|
},
|
||||||
cursorUndo: {
|
{
|
||||||
|
label: 'cursorUndo',
|
||||||
entry: 'vs/editor/contrib/cursorUndo/cursorUndo',
|
entry: 'vs/editor/contrib/cursorUndo/cursorUndo',
|
||||||
},
|
},
|
||||||
dnd: {
|
{
|
||||||
|
label: 'dnd',
|
||||||
entry: 'vs/editor/contrib/dnd/dnd',
|
entry: 'vs/editor/contrib/dnd/dnd',
|
||||||
},
|
},
|
||||||
find: {
|
{
|
||||||
|
label: 'find',
|
||||||
entry: 'vs/editor/contrib/find/findController',
|
entry: 'vs/editor/contrib/find/findController',
|
||||||
},
|
},
|
||||||
folding: {
|
{
|
||||||
|
label: 'folding',
|
||||||
entry: 'vs/editor/contrib/folding/folding',
|
entry: 'vs/editor/contrib/folding/folding',
|
||||||
},
|
},
|
||||||
fontZoom: {
|
{
|
||||||
|
label: 'fontZoom',
|
||||||
entry: 'vs/editor/contrib/fontZoom/fontZoom',
|
entry: 'vs/editor/contrib/fontZoom/fontZoom',
|
||||||
},
|
},
|
||||||
format: {
|
{
|
||||||
|
label: 'format',
|
||||||
entry: 'vs/editor/contrib/format/formatActions',
|
entry: 'vs/editor/contrib/format/formatActions',
|
||||||
},
|
},
|
||||||
goToDefinitionCommands: {
|
{
|
||||||
|
label: 'goToDefinitionCommands',
|
||||||
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionCommands',
|
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionCommands',
|
||||||
},
|
},
|
||||||
goToDefinitionMouse: {
|
{
|
||||||
|
label: 'goToDefinitionMouse',
|
||||||
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionMouse',
|
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionMouse',
|
||||||
},
|
},
|
||||||
gotoError: {
|
{
|
||||||
|
label: 'gotoError',
|
||||||
entry: 'vs/editor/contrib/gotoError/gotoError',
|
entry: 'vs/editor/contrib/gotoError/gotoError',
|
||||||
},
|
},
|
||||||
gotoLine: {
|
{
|
||||||
|
label: 'gotoLine',
|
||||||
entry: 'vs/editor/standalone/browser/quickOpen/gotoLine',
|
entry: 'vs/editor/standalone/browser/quickOpen/gotoLine',
|
||||||
},
|
},
|
||||||
hover: {
|
{
|
||||||
|
label: 'hover',
|
||||||
entry: 'vs/editor/contrib/hover/hover',
|
entry: 'vs/editor/contrib/hover/hover',
|
||||||
},
|
},
|
||||||
inPlaceReplace: {
|
{
|
||||||
|
label: 'inPlaceReplace',
|
||||||
entry: 'vs/editor/contrib/inPlaceReplace/inPlaceReplace',
|
entry: 'vs/editor/contrib/inPlaceReplace/inPlaceReplace',
|
||||||
},
|
},
|
||||||
inspectTokens: {
|
{
|
||||||
|
label: 'inspectTokens',
|
||||||
entry: 'vs/editor/standalone/browser/inspectTokens/inspectTokens',
|
entry: 'vs/editor/standalone/browser/inspectTokens/inspectTokens',
|
||||||
},
|
},
|
||||||
iPadShowKeyboard: {
|
{
|
||||||
|
label: 'iPadShowKeyboard',
|
||||||
entry: 'vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard',
|
entry: 'vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard',
|
||||||
},
|
},
|
||||||
linesOperations: {
|
{
|
||||||
|
label: 'linesOperations',
|
||||||
entry: 'vs/editor/contrib/linesOperations/linesOperations',
|
entry: 'vs/editor/contrib/linesOperations/linesOperations',
|
||||||
},
|
},
|
||||||
links: {
|
{
|
||||||
|
label: 'links',
|
||||||
entry: 'vs/editor/contrib/links/links',
|
entry: 'vs/editor/contrib/links/links',
|
||||||
},
|
},
|
||||||
multicursor: {
|
{
|
||||||
|
label: 'multicursor',
|
||||||
entry: 'vs/editor/contrib/multicursor/multicursor',
|
entry: 'vs/editor/contrib/multicursor/multicursor',
|
||||||
},
|
},
|
||||||
parameterHints: {
|
{
|
||||||
|
label: 'parameterHints',
|
||||||
entry: 'vs/editor/contrib/parameterHints/parameterHints',
|
entry: 'vs/editor/contrib/parameterHints/parameterHints',
|
||||||
},
|
},
|
||||||
quickCommand: {
|
{
|
||||||
|
label: 'quickCommand',
|
||||||
entry: 'vs/editor/standalone/browser/quickOpen/quickCommand',
|
entry: 'vs/editor/standalone/browser/quickOpen/quickCommand',
|
||||||
},
|
},
|
||||||
quickOutline: {
|
{
|
||||||
|
label: 'quickOutline',
|
||||||
entry: 'vs/editor/standalone/browser/quickOpen/quickOutline',
|
entry: 'vs/editor/standalone/browser/quickOpen/quickOutline',
|
||||||
},
|
},
|
||||||
referenceSearch: {
|
{
|
||||||
|
label: 'referenceSearch',
|
||||||
entry: [
|
entry: [
|
||||||
'vs/editor/contrib/referenceSearch/referenceSearch',
|
'vs/editor/contrib/referenceSearch/referenceSearch',
|
||||||
'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch',
|
'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
rename: {
|
{
|
||||||
|
label: 'rename',
|
||||||
entry: 'vs/editor/contrib/rename/rename',
|
entry: 'vs/editor/contrib/rename/rename',
|
||||||
},
|
},
|
||||||
smartSelect: {
|
{
|
||||||
|
label: 'smartSelect',
|
||||||
entry: 'vs/editor/contrib/smartSelect/smartSelect',
|
entry: 'vs/editor/contrib/smartSelect/smartSelect',
|
||||||
},
|
},
|
||||||
snippets: {
|
{
|
||||||
|
label: 'snippets',
|
||||||
entry: 'vs/editor/contrib/snippet/snippetController2',
|
entry: 'vs/editor/contrib/snippet/snippetController2',
|
||||||
},
|
},
|
||||||
suggest: {
|
{
|
||||||
|
label: 'suggest',
|
||||||
entry: 'vs/editor/contrib/suggest/suggestController',
|
entry: 'vs/editor/contrib/suggest/suggestController',
|
||||||
},
|
},
|
||||||
toggleHighContrast: {
|
{
|
||||||
|
label: 'toggleHighContrast',
|
||||||
entry: 'vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast',
|
entry: 'vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast',
|
||||||
},
|
},
|
||||||
toggleTabFocusMode: {
|
{
|
||||||
|
label: 'toggleTabFocusMode',
|
||||||
entry: 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode',
|
entry: 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode',
|
||||||
},
|
},
|
||||||
transpose: {
|
{
|
||||||
|
label: 'transpose',
|
||||||
entry: 'vs/editor/contrib/caretOperations/transpose',
|
entry: 'vs/editor/contrib/caretOperations/transpose',
|
||||||
},
|
},
|
||||||
wordHighlighter: {
|
{
|
||||||
|
label: 'wordHighlighter',
|
||||||
entry: 'vs/editor/contrib/wordHighlighter/wordHighlighter',
|
entry: 'vs/editor/contrib/wordHighlighter/wordHighlighter',
|
||||||
},
|
},
|
||||||
wordOperations: {
|
{
|
||||||
|
label: 'wordOperations',
|
||||||
entry: 'vs/editor/contrib/wordOperations/wordOperations',
|
entry: 'vs/editor/contrib/wordOperations/wordOperations',
|
||||||
},
|
},
|
||||||
wordPartOperations: {
|
{
|
||||||
|
label: 'wordPartOperations',
|
||||||
entry: 'vs/editor/contrib/wordPartOperations/wordPartOperations',
|
entry: 'vs/editor/contrib/wordPartOperations/wordPartOperations',
|
||||||
},
|
},
|
||||||
};
|
];
|
||||||
|
|
||||||
|
export const featuresById: { [feature: string]: IFeatureDefinition; } = {};
|
||||||
|
featuresArr.forEach(feature => featuresById[feature.label] = feature);
|
@ -0,0 +1,261 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import * as webpack from 'webpack';
|
||||||
|
import * as loaderUtils from 'loader-utils';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import { AddWorkerEntryPointPlugin } from './plugins/AddWorkerEntryPointPlugin';
|
||||||
|
import { languagesById } from './languages';
|
||||||
|
import { featuresById } from './features';
|
||||||
|
import { IFeatureDefinition } from './types';
|
||||||
|
|
||||||
|
const INCLUDE_LOADER_PATH = require.resolve('./loaders/include');
|
||||||
|
|
||||||
|
const EDITOR_MODULE: IFeatureDefinition = {
|
||||||
|
label: 'editorWorkerService',
|
||||||
|
entry: undefined,
|
||||||
|
worker: {
|
||||||
|
id: 'vs/editor/editor',
|
||||||
|
entry: 'vs/editor/editor.worker',
|
||||||
|
fallback: undefined
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a resolved path for a given Monaco file.
|
||||||
|
*/
|
||||||
|
function resolveMonacoPath(filePath: string): string {
|
||||||
|
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: string, entry: string): string {
|
||||||
|
return loaderUtils.interpolateName(<any>{ resourcePath: entry }, filename, {
|
||||||
|
content: fs.readFileSync(resolveMonacoPath(entry))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFeaturesIds(userFeatures: string[]): string[] {
|
||||||
|
function notContainedIn(arr: string[]) {
|
||||||
|
return (element: string) => arr.indexOf(element) === -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let featuresIds: string[];
|
||||||
|
|
||||||
|
if (userFeatures.length) {
|
||||||
|
const excludedFeatures = userFeatures.filter(f => f[0] === '!').map(f => f.slice(1));
|
||||||
|
if (excludedFeatures.length) {
|
||||||
|
featuresIds = Object.keys(featuresById).filter(notContainedIn(excludedFeatures))
|
||||||
|
} else {
|
||||||
|
featuresIds = userFeatures;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
featuresIds = Object.keys(featuresById);
|
||||||
|
}
|
||||||
|
|
||||||
|
return featuresIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IMonacoEditorWebpackPluginOpts {
|
||||||
|
/**
|
||||||
|
* Include only a subset of the languages supported.
|
||||||
|
*/
|
||||||
|
languages?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Include only a subset of the editor features.
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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-
|
||||||
|
* origin when using a CDN for other static resources.
|
||||||
|
* Use e.g. '/' if you want to load your resources from the current origin.
|
||||||
|
*/
|
||||||
|
publicPath?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IInternalMonacoEditorWebpackPluginOpts {
|
||||||
|
languages: IFeatureDefinition[];
|
||||||
|
features: IFeatureDefinition[];
|
||||||
|
filename: string;
|
||||||
|
publicPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MonacoEditorWebpackPlugin implements webpack.Plugin {
|
||||||
|
|
||||||
|
private readonly options: IInternalMonacoEditorWebpackPluginOpts;
|
||||||
|
|
||||||
|
constructor(options: IMonacoEditorWebpackPluginOpts = {}) {
|
||||||
|
const languages = options.languages || Object.keys(languagesById);
|
||||||
|
const features = getFeaturesIds(options.features || []);
|
||||||
|
this.options = {
|
||||||
|
languages: coalesce(languages.map(id => languagesById[id])),
|
||||||
|
features: coalesce(features.map(id => featuresById[id])),
|
||||||
|
filename: options.filename || "[name].worker.js",
|
||||||
|
publicPath: options.publicPath || '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler: webpack.Compiler): void {
|
||||||
|
const { languages, features, filename, publicPath } = this.options;
|
||||||
|
const compilationPublicPath = getCompilationPublicPath(compiler);
|
||||||
|
const modules = [EDITOR_MODULE].concat(languages).concat(features);
|
||||||
|
const workers: ILabeledWorkerDefinition[] = coalesce(modules.map(
|
||||||
|
({ label, worker }) => worker && (mixin({ label }, worker))
|
||||||
|
));
|
||||||
|
const rules = createLoaderRules(languages, features, workers, filename, publicPath, compilationPublicPath);
|
||||||
|
const plugins = createPlugins(workers, filename);
|
||||||
|
addCompilerRules(compiler, rules);
|
||||||
|
addCompilerPlugins(compiler, plugins);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILabeledWorkerDefinition {
|
||||||
|
label: string;
|
||||||
|
id: string;
|
||||||
|
entry: string;
|
||||||
|
fallback: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCompilerRules(compiler: webpack.Compiler, rules: webpack.RuleSetRule[]): void {
|
||||||
|
const compilerOptions = compiler.options;
|
||||||
|
if (!compilerOptions.module) {
|
||||||
|
compilerOptions.module = { rules: rules };
|
||||||
|
} else {
|
||||||
|
const moduleOptions = compilerOptions.module;
|
||||||
|
moduleOptions.rules = (moduleOptions.rules || []).concat(rules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCompilerPlugins(compiler: webpack.Compiler, plugins: webpack.Plugin[]) {
|
||||||
|
plugins.forEach((plugin) => plugin.apply(compiler));
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCompilationPublicPath(compiler: webpack.Compiler): string {
|
||||||
|
return compiler.options.output && compiler.options.output.publicPath || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function createLoaderRules(languages: IFeatureDefinition[], features: IFeatureDefinition[], workers: ILabeledWorkerDefinition[], filename: string, pluginPublicPath: string, compilationPublicPath: string): webpack.RuleSetRule[] {
|
||||||
|
if (!languages.length && !features.length) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const languagePaths = flatArr(coalesce(languages.map(({ entry }) => entry)));
|
||||||
|
const featurePaths = flatArr(coalesce(features.map(({ entry }) => entry)));
|
||||||
|
const workerPaths = fromPairs(workers.map(({ label, entry }) => [label, getWorkerFilename(filename, entry)]));
|
||||||
|
if (workerPaths['typescript']) {
|
||||||
|
// javascript shares the same worker
|
||||||
|
workerPaths['javascript'] = workerPaths['typescript'];
|
||||||
|
}
|
||||||
|
if (workerPaths['css']) {
|
||||||
|
// scss and less share the same worker
|
||||||
|
workerPaths['less'] = workerPaths['css'];
|
||||||
|
workerPaths['scss'] = workerPaths['css'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workerPaths['html']) {
|
||||||
|
// handlebars, razor and html share the same worker
|
||||||
|
workerPaths['handlebars'] = workerPaths['html'];
|
||||||
|
workerPaths['razor'] = workerPaths['html'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the public path from which to load worker JS files. In order of precedence:
|
||||||
|
// 1. Plugin-specific public path.
|
||||||
|
// 2. Dynamic runtime public path.
|
||||||
|
// 3. Compilation public path.
|
||||||
|
const pathPrefix = Boolean(pluginPublicPath)
|
||||||
|
? JSON.stringify(pluginPublicPath)
|
||||||
|
: `typeof __webpack_public_path__ === 'string' ` +
|
||||||
|
`? __webpack_public_path__ ` +
|
||||||
|
`: ${JSON.stringify(compilationPublicPath)}`
|
||||||
|
|
||||||
|
const globals = {
|
||||||
|
'MonacoEnvironment': `(function (paths) {
|
||||||
|
function stripTrailingSlash(str) {
|
||||||
|
return str.replace(/\\/$/, '');
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
getWorkerUrl: function (moduleId, label) {
|
||||||
|
var pathPrefix = ${pathPrefix};
|
||||||
|
return (pathPrefix ? stripTrailingSlash(pathPrefix) + '/' : '') + paths[label];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(${JSON.stringify(workerPaths, null, 2)})`,
|
||||||
|
};
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
test: /monaco-editor[/\\]esm[/\\]vs[/\\]editor[/\\]editor.(api|main).js/,
|
||||||
|
use: [{
|
||||||
|
loader: INCLUDE_LOADER_PATH,
|
||||||
|
options: {
|
||||||
|
globals,
|
||||||
|
pre: featurePaths.map((importPath) => resolveMonacoPath(importPath)),
|
||||||
|
post: languagePaths.map((importPath) => resolveMonacoPath(importPath)),
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPlugins(workers: ILabeledWorkerDefinition[], filename: string): AddWorkerEntryPointPlugin[] {
|
||||||
|
return (
|
||||||
|
(<AddWorkerEntryPointPlugin[]>[])
|
||||||
|
.concat(uniqBy(workers, ({ id }) => id).map(({ id, entry }) =>
|
||||||
|
new AddWorkerEntryPointPlugin({
|
||||||
|
id,
|
||||||
|
entry: resolveMonacoPath(entry),
|
||||||
|
filename: getWorkerFilename(filename, entry),
|
||||||
|
plugins: [
|
||||||
|
new webpack.optimize.LimitChunkCountPlugin({ maxChunks: 1 }),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatArr<T>(items: (T | T[])[]): T[] {
|
||||||
|
return items.reduce((acc: T[], item: T | T[]) => {
|
||||||
|
if (Array.isArray(item)) {
|
||||||
|
return (<T[]>[]).concat(acc).concat(item);
|
||||||
|
}
|
||||||
|
return (<T[]>[]).concat(acc).concat([item]);
|
||||||
|
}, <T[]>[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromPairs<T>(values: [string, T][]): { [key: string]: T; } {
|
||||||
|
return values.reduce((acc, [key, value]) => Object.assign(acc, { [key]: value }), <{ [key: string]: T; }>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
function uniqBy<T>(items: T[], iteratee: (item: T) => string): T[] {
|
||||||
|
const keys: { [key: string]: boolean; } = {};
|
||||||
|
return items.reduce((acc, item) => {
|
||||||
|
const key = iteratee(item);
|
||||||
|
if (key in keys) { return acc; }
|
||||||
|
keys[key] = true;
|
||||||
|
acc.push(item);
|
||||||
|
return acc;
|
||||||
|
}, <T[]>[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mixin<DEST, SRC>(dest: DEST, src: SRC): DEST & SRC {
|
||||||
|
for (let prop in src) {
|
||||||
|
if (Object.hasOwnProperty.call(src, prop)) {
|
||||||
|
(<any>dest)[prop] = src[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return <any>dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
function coalesce<T>(array: ReadonlyArray<T | undefined | null>): T[] {
|
||||||
|
return <T[]>array.filter(Boolean);
|
||||||
|
}
|
||||||
|
|
||||||
|
export = MonacoEditorWebpackPlugin;
|
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
export interface IWorkerDefinition {
|
||||||
|
id: string;
|
||||||
|
entry: string;
|
||||||
|
fallback: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IFeatureDefinition {
|
||||||
|
label: string;
|
||||||
|
entry: string | string[] | undefined;
|
||||||
|
worker?: IWorkerDefinition;
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "out",
|
||||||
|
"target": "es6",
|
||||||
|
"declaration": true,
|
||||||
|
"strict": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue