I am attempting to use the ace
text editor with angular
, and one of the needed behaviors requires a call to ace.require
.
I've included the appropriate files, but I am seeing that if I minify my javascript source, that doesn't work anymore. This is clearly because the path becomes invalid, but I'm not sure how to handle the situation except to manually load the mentioned files outside of my optimized bundles. I am using ASP.NET MVC Web Optimization Framework
to load my javascripts as "bundles" that are compact and minified.
I am using ui-ace directive to load it, but I have tested without any directive and the behavior is the same whether or not I am going through angular.
Has anyone else discovered a workaround to this?
It's pretty simple code ...
bundles.Add( new ScriptBundle( "~/bundles/js/ace" )
// include the ace text editor
.Include( "~/application/assets/scripts/ace/ace.js" )
.Include( "~/application/assets/scripts/ace/ext-language_tools.js" )));
if (angular.isDefined(opts.require)) {
opts.require.forEach(function (n) {
window.ace.require(n);
});
}
This can also just be typed explicitly as ...
ace.require('ace/ext/language_tools');
<div ng-model="Model.Scripting"
ui-ace="{
useWrapMode: true,
showGutter: true,
theme: 'chrome',
mode: 'javascript',
require: ['ace/ext/language_tools'],
advanced: {
enableSnippets: true,
enableBasicAutocompletion: true,
enableLiveAutocompletion: true
}
}">
</div>
Since I cannot figure out a way to get the whole thing to you exactly as it needs to be, I've recreated the behavior using nodejs
, bower
, and gulp
.
Start by running these commands in nodejs, in a new folder.
npm install bower
npm install gulp
npm install gulp-concat
npm install gulp-rename
npm install gulp-uglify
npm install run-sequence
bower install angular
bower install ace-builds
bower install angular-ui-ace
You can use this gulpfile.js
to build the script file.
var
gulp = require('gulp'),
concat = require('gulp-concat'),
rename = require('gulp-rename'),
uglify = require('gulp-uglify'),
sequence = require('run-sequence');
gulp.task('default', function() {
return sequence([
"ace"
]);
});
gulp.task('ace', function() {
return gulp.src([
'bower_components/angular/angular.js',
'bower_components/angular-ui-ace/ui-ace.js',
'bower_components/ace-builds/src-noconflict/ace.js',
'bower_components/ace-builds/src-noconflict/mode-javascript.js',
'bower_components/ace-builds/src-noconflict/worker-javascript.js',
'bower_components/ace-builds/src-noconflict/theme-chrome.js',
'bower_components/ace-builds/src-noconflict/snippets/text.js',
'bower_components/ace-builds/src-noconflict/snippets/javascript.js'])
.pipe(concat('scripts.js'))
.pipe(uglify())
.pipe(gulp.dest('js'));
});
This is an HTML file that can reproduce the problem.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<script type="text/javascript" src="js/scripts.js"></script>
<script type="text/javascript">
(function () {
var ace = window.ace = window.ace || { };
ace.initialize = function(editor) {
ace.require("ace/ext/language_tools");
editor.setTheme("ace/theme/chrome");
editor.getSession().setMode("ace/mode/javascript");
// options
editor.setOptions({
showGutter: true,
showPrintMargin: false,
enableBasicAutocompletion: true,
enableSnippets: true,
enableLiveAutocompletion: true,
fontSize: '14px',
fontFamily: 'Consolas'
});
};
})();
</script>
<script type="text/javascript">
angular.module('app', ['ui.ace'])
.controller('HomeController',['$scope', function($scope){
$scope.aceLoaded = function(_editor){
ace.initialize(_editor);
};
$scope.Model = {
Scripting: ""
}
}]);
</script>
</head>
<body ng-app="app" ng-controller="HomeController">
<div ui-ace="{ onLoad: aceLoaded }"></div>
</body>
</html>
For ace.require to work you need to add ext-language_tools to your gulp.task("ace")
'bower_components/ace-builds/src-noconflict/ace.js',
'bower_components/ace-builds/src-noconflict/ext-language_tools.js',
'bower_components/ace-builds/src-noconflict/mode-javascript.js',
bower_components/ace-builds/src-noconflict/worker-javascript.js
isn't needed in the bundle since it needs to be loaded in the webworker. For that to work you need to configure workerPath to point to the right folder
ace.initialize = function(editor) {
ace.require("ace/config").set("workerPath",
"bower_components/ace-builds/src-min-noconflict");
ace.require("ace/ext/language_tools");
and for ace not being visible initially because of it's height being set to 0 see this question: Ace editor doesn't work with bootstrap
also note that fontFamily: 'Consolas'
might cause problems on systems where that font is missing, so it's better to add a fallback to monospace like fontFamily: 'Consolas', monospace