在webpack中使用monaco-editor


前言

我查過網上的教程,大部分都是基於vue或者react框架,很少有教程是基於純粹的webpack來的,這篇文章記錄我在webpack上使用monaco-editor的過程,以補充網上在這方面資料的缺失。本文章會根據我的開發隨時進行更新。

使用

monaco的使用介紹,網上有很多,大家可以參考這篇文章進行大概的了解。

點擊跳轉

自己總結的使用過程

1、安裝。

npm install monaco-editor -save

2、在頁面中使用

在HTML中創建一個容器,然后使用下面的代碼進行初始化就可以得到一個在線編輯器了,但是現在這個編輯器也只是編輯器,什么輔助功能都沒有,比如代碼提示、右鍵菜單等等。

 
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
const monacoInstance=monaco.editor.create(document.getElementById("monaco"),{
value:`console.log("hello,world")`,

language:"javascript"

})

效果圖:

3、開啟輔助功能

如何開啟輔助功能,一種是我們根據自己的需要把輔助的文件引入到頁面中,方法參考【使用】章節里提供的地址,另外一種就是用webpack來實現。

安裝monaco-editor-webpack-plugin這個模塊。

npm install monaco-editor-webpack-plugin

在webpack.config.js中進行配置,MonacoWebpackPlugin可以接受language和features來配置輔助功能,具體配置參數可以查看npm官網即可。

 

const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

module.exports = {
...

plugins: [

new MonacoWebpackPlugin()

]

}

效果圖如下:

不過這里有幾點注意的,這是博主在使用過程中發現的一些情況:

1)、如果你得webpack項目使用了HtmlWebpackPlugin來實現多頁面配置,那么通過monaco-editor-webpack-plugin生成的一些文件的引用路徑將會受到HtmlWebpackPlugin這個配置的影響。例如我使用如下代碼動態配置HTML模板的信息,其中filename不僅可以從命名文件還可以設置其路徑,假設我將filename改為`pages/${name}.html`,將HTML文件放在pages這個路徑下,那么monaco-editor-webpack-plugin生成的所有文件在引用的時候都會加上pages這個路徑,原因未知,博主排查了好久都不清楚為啥,所以只能放在根目錄下。如果有知道的歡迎指出。

 

var getHtmlConfig = function(name,chunks){

return {
template:`./src/app/pages/${name}.html`,

filename:`${name}.html`,

inject:true, // 將js資源插入到body元素底部

hash:false,

chunks:[name, 'runtime','libs', 'commons']

}

}

2)、monaco-editor-webpack-plugin參數中filename僅更改worker文件的名字,而無法更改其他生成的JS文件名稱。

3)、MonacoWebpackPlugin的language參數的配置會影響右鍵菜單。經測試:如果language中如果沒有引入typescript,右鍵菜單和控制面板部分功能將消失。

4、如何設置菜單中文顯示效果

這個功能折騰了樓主好久時間。網上也沒有系統的相關資料。不過能在一些文章中零星的看到有人使用下面的代碼進行配置。

 
require.config({
'vs/nls': {
availableLanguages: {

'*': 'zh-cn'

}

}

});

可是當你把這段代碼復制到自己的代碼中又發現完全無法執行。那怎么辦?

這里需要涉及到另外兩個模塊。monaco-editor-esm-webpack-plugin和monaco-editor-nls。其中monaco-editor-esm-webpack-plugin和上面的monaco-editor-webpack-plugin這個不一樣,前者需要依賴后者,也就是說你要使用前者,就必須先安裝后者。先安裝兩個模塊。

 

npm install --save monaco-editor-nls

npm install --save-dev monaco-editor-esm-webpack-plugin

改寫webpack.config.js,需要注意的是rules里也需要添加MonacoWebpackPlugin.loader

 

// 去除monaco-editor-webpack-plugin,改為monaco-editor-esm-webpack-plugin

const MonacoWebpackPlugin = require('monaco-editor-esm-webpack-plugin');

module.exports = {

module: {

rules: [

{

test: /\.js/,

enforce: 'pre',

include: /node_modules[\\\/]monaco-editor[\\\/]esm/,

use: MonacoWebpackPlugin.loader

},

]

}

plugins: [

new MonacoWebpackPlugin()

]

}

然后在頁面的JS中添加如下代碼,這些代碼必須添加在引入'monaco-editor/esm/vs/editor/editor.api.js';之前

 

import { setLocaleData } from 'monaco-editor-nls';

import zh_CN from 'monaco-editor-nls/locale/zh-hans';
setLocaleData(zh_CN);

接着重新編輯文件,你會發現編譯控制台提示報錯,在monaco-editor/esm/vs/editor/contrib下缺少goToDefinition文件夾。其實還缺少了一個referenceSearch。如何解決?首先說明一下,這兩個文件夾其實並沒有缺少,只是在monaco-editor@0.19.0版本以上,微軟把這些文件統一放到了gotoSymbol這個文件夾,你可以把monaco-editor安裝為0.18.1這個版本就可以使用,不過還是得進行一些插件源代碼修改。如果我一定要安裝@0.20.0怎么辦,那只需要修改\node_modules\monaco-editor-esm-webpack-plugin\node_modules\monaco-editor-webpack-plugin\features.js這個文件即可。

 

// 刪除一下代碼

goToDefinitionCommands: {
entry: 'vs/editor/contrib/goToDefinition/goToDefinitionCommands',

worker: undefined,

},

goToDefinitionMouse: {

entry: 'vs/editor/contrib/goToDefinition/goToDefinitionMouse',

worker: undefined,

},

referenceSearch: {

entry: [

'vs/editor/contrib/referenceSearch/referenceSearch',

'vs/editor/standalone/browser/referenceSearch/standaloneReferenceSearch',

],

worker: undefined,

}

// 新增以下代碼

gotoSymbol:{

entry: 'vs/editor/contrib/gotoSymbol/goToCommands',

worker: undefined

}

按照上述操作修改后就可以正常編譯了。可是編譯后,你打開項目你會發現菜單什么還是英文的。這又是啥子情況,明明都按照要求更改了。這個問題我也不清楚是為啥,不過按照下面的改法就行。在一開始我們引入editor.api.js的時候是使用import進行引入的,只要把它改為require引入就行。

 

const monaco = require('monaco-editor/esm/vs/editor/editor.api');

// import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js';
const monacoInstance = monaco.editor.create( document.getElementById("monaco"),{

value: `console.log(123)`,

contextmenu: true,

language: 'javascript',

theme: 'vs-dark'

})

到此菜單漢化就完成了,重新打包運行后效果如下:

 

5、編輯器功能(更新:2020年8月24日)

 1)、動態賦值

 
monacoInstance = monaco.editor.create( document.getElementById("monaco"),{
value: ``,
contextmenu: true,

language: 'javascript',

theme: 'vs-dark'

})

monacoInstance.setValue(res);

2)、動態修改語言

 

monaco.editor.setModelLanguage(monacoInstance.getModel(), 'html');

monaco.editor.setModelLanguage(monacoInstance.getModel(), 'javascript');

3)、獲取光標位置

 

monacoInstance.getPosition();

// 返回參數
// lineNumber 行數

// column 列數

4)、設置光標位置。

 

// 兩個參數最好都寫,不然控制台會報錯

monacoInstance.setPosition({
lineNumber: 115,

column: 1

})

5)、聚焦編輯器

monacoInstance.focus();

6)、編輯器滾動到頂部

 

monacoInstance.setScrollPosition({

scrollTop: 0,
scrollLeft: 0

});

7)、獲取當前編輯器內容行數

monacoInstance.getModel().getLineCount()

8)、獲取某一行的列數

monacoInstance.getModel().getLineLength(2)

 9)、在特定行插入數據

 

function insertValueByCurrentPosition(value) {

var p = monacoInstance.getPosition();
monacoInstance.executeEdits( "",

[

{

range: new monaco.Range(p.lineNumber,

p.column,

p.lineNumber,

p.column),

text: value

}

]

);

}

6、monaco-editor使用到的JS文件如何壓縮(2020年4月28日11:49:58)

我們在webpack中使用到壓縮JS模塊一般都是使用uglifyjs-webpack-plugin。如果我們在項目中使用了monaco-editor的話,在使用uglifyjs-webpack-plugin壓縮editor需要的JS的時候,你會發現控制台輸出錯誤信息,會出現兩種錯誤提示,一種是關於worker.js相關的錯誤,一個是Unexpected token: name «__insane_func», expected: punc «;»。上面兩個錯誤本質上都是因為monaco-editor中使用了最新的ESM語法,uglifyjs-webpack-plugin無法正常解析導致的。處理辦法有兩種:

1)、繼續使用uglifyjs-webpack-plugin。在exclude參數中添加worker.js,然后在chunkFilter中去除提示Unexpected token: name «__insane_func», expected: punc «;»錯誤的文件。不對這些文件進行壓縮就可以正常編譯。

 

module.exports = {

optimization: {
minimizer: [

new UglifyJSPlugin({ //目的是為了編譯環境清除控制台以及關閉注釋

exclude: /\.min\.js|\.worker\.js|\/libs-bundle$/,

cache: true,

parallel: true, // 開啟並行壓縮,充分利用cpu

extractComments: false, // 移除注釋

chunkFilter: (chunk) => { // 需要加上這個,不然monaco-editor采用新的es語法,uglify無法解析

if (chunk.name == 'libs') {

return false;

}

return true

},

uglifyOptions: {

output: {

comments: false // 保留所有的注釋

},

compress: {

drop_debugger: true,

drop_console: true // 刪除所有的 `console` 語句,可以兼容ie瀏覽器

}

}

}),

]

}

}

2)、不是用uglifyjs-webpack-plugin,將該模塊替換為terser-webpack-plugin。這兩個插件參數和使用方法基本是一致,可以理解為后者是前者的升級版。參考資料:【傳送門1傳送門2傳送門3】。下面給出我的配置代碼。

 

module.exports = {

optimization: {
minimize: true,

minimizer: [

new TerserPlugin({ //目的是為了編譯環境清除控制台以及關閉注釋

exclude: /\.min\.js$/,

cache: true,

parallel: true, // 開啟並行壓縮,充分利用cpu

extractComments: false, // 移除注釋

terserOptions: {

output: {

comments: false // 保留所有的注釋

},

compress: {

drop_debugger: true,

drop_console: true // 刪除所有的 `console` 語句,可以兼容ie瀏覽器

}

}

}),

]

}

}

后記:2020年4月23日15:22:48  在使用這個編輯器過程中,博主前前后后折騰了好久,特別是那個莫名添加路徑和漢化這兩點上,花費了很多的時間。百度過谷歌過都沒有找到解決方案。不過幸好,最終還是做到自己想要的效果了。在此感謝上述涉及的插件模塊的開發者。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM