Convert to TypeScript
parent
e032f77fb9
commit
0bd24b523b
@ -1,3 +1,4 @@
|
||||
/node_modules/
|
||||
/test/node_modules/
|
||||
/test/dist/*.js
|
||||
/out/
|
||||
|
@ -1 +1,2 @@
|
||||
/src/
|
||||
/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 = {
|
||||
accessibilityHelp: {
|
||||
import { IFeatureDefinition } from "./types";
|
||||
|
||||
const featuresArr: IFeatureDefinition[] = [
|
||||
{
|
||||
label: 'accessibilityHelp',
|
||||
entry: 'vs/editor/standalone/browser/accessibilityHelp/accessibilityHelp',
|
||||
},
|
||||
bracketMatching: {
|
||||
{
|
||||
label: 'bracketMatching',
|
||||
entry: 'vs/editor/contrib/bracketMatching/bracketMatching',
|
||||
},
|
||||
caretOperations: {
|
||||
{
|
||||
label: 'caretOperations',
|
||||
entry: 'vs/editor/contrib/caretOperations/caretOperations',
|
||||
},
|
||||
clipboard: {
|
||||
{
|
||||
label: 'clipboard',
|
||||
entry: 'vs/editor/contrib/clipboard/clipboard',
|
||||
},
|
||||
codeAction: {
|
||||
{
|
||||
label: 'codeAction',
|
||||
entry: 'vs/editor/contrib/codeAction/codeActionContributions',
|
||||
},
|
||||
codelens: {
|
||||
{
|
||||
label: 'codelens',
|
||||
entry: 'vs/editor/contrib/codelens/codelensController',
|
||||
},
|
||||
colorDetector: {
|
||||
{
|
||||
label: 'colorDetector',
|
||||
entry: 'vs/editor/contrib/colorPicker/colorDetector',
|
||||
},
|
||||
comment: {
|
||||
{
|
||||
label: 'comment',
|
||||
entry: 'vs/editor/contrib/comment/comment',
|
||||
},
|
||||
contextmenu: {
|
||||
{
|
||||
label: 'contextmenu',
|
||||
entry: 'vs/editor/contrib/contextmenu/contextmenu',
|
||||
},
|
||||
coreCommands: {
|
||||
{
|
||||
label: 'coreCommands',
|
||||
entry: 'vs/editor/browser/controller/coreCommands',
|
||||
},
|
||||
cursorUndo: {
|
||||
{
|
||||
label: 'cursorUndo',
|
||||
entry: 'vs/editor/contrib/cursorUndo/cursorUndo',
|
||||
},
|
||||
dnd: {
|
||||
{
|
||||
label: 'dnd',
|
||||
entry: 'vs/editor/contrib/dnd/dnd',
|
||||
},
|
||||
find: {
|
||||
{
|
||||
label: 'find',
|
||||
entry: 'vs/editor/contrib/find/findController',
|
||||
},
|
||||
folding: {
|
||||
{
|
||||
label: 'folding',
|
||||
entry: 'vs/editor/contrib/folding/folding',
|
||||
},
|
||||
fontZoom: {
|
||||
{
|
||||
label: 'fontZoom',
|
||||
entry: 'vs/editor/contrib/fontZoom/fontZoom',
|
||||
},
|
||||
format: {
|
||||
{
|
||||
label: 'format',
|
||||
entry: 'vs/editor/contrib/format/formatActions',
|
||||
},
|
||||
goToDefinitionCommands: {
|
||||
{
|
||||
label: 'goToDefinitionCommands',
|
||||
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionCommands',
|
||||
},
|
||||
goToDefinitionMouse: {
|
||||
{
|
||||
label: 'goToDefinitionMouse',
|
||||
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionMouse',
|
||||
},
|
||||
gotoError: {
|
||||
{
|
||||
label: 'gotoError',
|
||||
entry: 'vs/editor/contrib/gotoError/gotoError',
|
||||
},
|
||||
gotoLine: {
|
||||
{
|
||||
label: 'gotoLine',
|
||||
entry: 'vs/editor/standalone/browser/quickOpen/gotoLine',
|
||||
},
|
||||
hover: {
|
||||
{
|
||||
label: 'hover',
|
||||
entry: 'vs/editor/contrib/hover/hover',
|
||||
},
|
||||
inPlaceReplace: {
|
||||
{
|
||||
label: 'inPlaceReplace',
|
||||
entry: 'vs/editor/contrib/inPlaceReplace/inPlaceReplace',
|
||||
},
|
||||
inspectTokens: {
|
||||
{
|
||||
label: 'inspectTokens',
|
||||
entry: 'vs/editor/standalone/browser/inspectTokens/inspectTokens',
|
||||
},
|
||||
iPadShowKeyboard: {
|
||||
{
|
||||
label: 'iPadShowKeyboard',
|
||||
entry: 'vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard',
|
||||
},
|
||||
linesOperations: {
|
||||
{
|
||||
label: 'linesOperations',
|
||||
entry: 'vs/editor/contrib/linesOperations/linesOperations',
|
||||
},
|
||||
links: {
|
||||
{
|
||||
label: 'links',
|
||||
entry: 'vs/editor/contrib/links/links',
|
||||
},
|
||||
multicursor: {
|
||||
{
|
||||
label: 'multicursor',
|
||||
entry: 'vs/editor/contrib/multicursor/multicursor',
|
||||
},
|
||||
parameterHints: {
|
||||
{
|
||||
label: 'parameterHints',
|
||||
entry: 'vs/editor/contrib/parameterHints/parameterHints',
|
||||
},
|
||||
quickCommand: {
|
||||
{
|
||||
label: 'quickCommand',
|
||||
entry: 'vs/editor/standalone/browser/quickOpen/quickCommand',
|
||||
},
|
||||
quickOutline: {
|
||||
{
|
||||
label: 'quickOutline',
|
||||
entry: 'vs/editor/standalone/browser/quickOpen/quickOutline',
|
||||
},
|
||||
referenceSearch: {
|
||||
{
|
||||
label: 'referenceSearch',
|
||||
entry: [
|
||||
'vs/editor/contrib/referenceSearch/referenceSearch',
|
||||
'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch',
|
||||
],
|
||||
},
|
||||
rename: {
|
||||
{
|
||||
label: 'rename',
|
||||
entry: 'vs/editor/contrib/rename/rename',
|
||||
},
|
||||
smartSelect: {
|
||||
{
|
||||
label: 'smartSelect',
|
||||
entry: 'vs/editor/contrib/smartSelect/smartSelect',
|
||||
},
|
||||
snippets: {
|
||||
{
|
||||
label: 'snippets',
|
||||
entry: 'vs/editor/contrib/snippet/snippetController2',
|
||||
},
|
||||
suggest: {
|
||||
{
|
||||
label: 'suggest',
|
||||
entry: 'vs/editor/contrib/suggest/suggestController',
|
||||
},
|
||||
toggleHighContrast: {
|
||||
{
|
||||
label: 'toggleHighContrast',
|
||||
entry: 'vs/editor/standalone/browser/toggleHighContrast/toggleHighContrast',
|
||||
},
|
||||
toggleTabFocusMode: {
|
||||
{
|
||||
label: 'toggleTabFocusMode',
|
||||
entry: 'vs/editor/contrib/toggleTabFocusMode/toggleTabFocusMode',
|
||||
},
|
||||
transpose: {
|
||||
{
|
||||
label: 'transpose',
|
||||
entry: 'vs/editor/contrib/caretOperations/transpose',
|
||||
},
|
||||
wordHighlighter: {
|
||||
{
|
||||
label: 'wordHighlighter',
|
||||
entry: 'vs/editor/contrib/wordHighlighter/wordHighlighter',
|
||||
},
|
||||
wordOperations: {
|
||||
{
|
||||
label: 'wordOperations',
|
||||
entry: 'vs/editor/contrib/wordOperations/wordOperations',
|
||||
},
|
||||
wordPartOperations: {
|
||||
{
|
||||
label: '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