I am building a web application and I want to use TinyMCE. I am using gulp and browserify. I have downloaded TinyMCE through npm and than I have required it in my app.js file and run the gulp command but I got this error Failed to load: root/js/themes/modern/theme.js. I think this is because TinyMCE needs additional files from its folder. My question is how to configurate TinyMCE to search those files in the node_modules/tinymce folder.
The answer here depends completely on how you are packaging up files in your Gulp build. I'm still working through the same problem right now, but here's a tip that might help.
In my case, I'm using the main-bower-files plugin to read my Bower config and then return a stream of all the main JS files from all of my dependencies I've installed with Bower. It looks like this:
var mainBowerFiles = require('main-bower-files');
gulp.task('vendor-src', function () {
return gulp.src(mainBowerFiles('**/*.js')
.pipe(uglify())
.pipe(concat('main.min.js'))
.pipe(gulp.dest('dist/'))
});
Unfortunately, this does not pick up any of the TinyMCE files, which are installed in my bower_components directory, because the 'tinymce' installed through Bower does not come with a package.json file. I think this is because you have the choice between using the regular and jQuery versions of TinyMCE, which are both in the package.
I had to change my Gulp task from above to get it to pick up the TinyMCE source code that I want (the jQuery version). That version looks like this:
var mainBowerFiles = require('main-bower-files');
gulp.task('vendor-src', function () {
return gulp.src(
mainBowerFiles('**/*.js', {
"overrides": {
"tinymce": {
"main": ["tinymce.jquery.js", "plugins/**/*.js", "themes/**/*.js"]
}
})
.pipe(uglify())
.pipe(concat('main.min.js'))
.pipe(gulp.dest('dist/'))
});
That will include all of the JS files associated with TinyMCE and add them to the "main bower files" list.
This is only a partial solution though because you also have to pick up the TinyMCE CSS and font files. And then if you're build is completely different or you're not using the main-bower-files plugin, this might not help either.
I had an open issue with the main-bower-files author who discouraged the use of it together with TinyMCE, probably due to the large number of extra files that must be included (?). See the following issue on Github.
I ended up just copying the tinymce folder to my dist/ through a simple gulp task. I use Bower and different paths probably, but you get the idea
gulp.task('bower-tinymce', function() {
//Copy resources from tinymce-dist that didn't make it in the bower-files
return gulp.src('src/main/resources/static/bower_components/tinymce-dist/**/*').pipe(gulp.dest('src/main/resources/static/dist/tinymce'));
});
Related
Problem
I'm currently trying to build a 3D web app based on three.js.
I'm using neovim as my development environment and YouCompleteMe as a completion system.
I installed tern to complete JS, and I added .tern-project file like this.
{
"libs": [
"browser",
"ecmascript",
],
"loadEagerly": [
],
"plugins": {
"threejs": {}
}
}
I also copied threejs.js and threejs.json to my project's directory generated by tern-threejs.
However, YouCompleteMe doesn't show semantic completion compared to tern-threejs's demo codemirror
Comparison:
codemirror:
neovim:
Note: I can't see any completion at all.
What seems to be the problem?
threejs.js is a tern plugin file and threejs.json is a tern library file. plugin files should be copied in tern/plugin directory and library files needs to be placed within tern/defs directory. These two directory exists within tern directory.
With 'YouCompleteMe' installed this dir path is: ~/.vim/YouCompleteMe/third_party/ycmd/third_party/tern-runtime/node_modules/tern. You only need to copy one of aforementioned files. Plugin file or lib file; and update your .tern-project file accordingly. so:
First ensure that you have enabled the Tern completer on YouCompleteMe. For example on my Mac, I had to run the following:
cd ~/.vim/bundle/YouCompleteMe
./install.py --tern-completer
See YouCompleteMe installation guide for details on how to do it on other environments.
Copy threejs.js then navigate to
~/.vim/YouCompleteMe/third_party/ycmd/third_party/tern-runtime/node_modules/tern/plugin/
and paste.
Update your project's .tern-project file as follows:
{
"libs": [
"browser",
"ecmascript",
],
"plugins": {
"es_modules": {},
"threejs": {}
}
}
Note that i've also included es_modules plugin (which is a plugin shipped with tern itself) as you are using ES6 module pattern system.
Instead of adding <script src="https://checkout.stripe.com/checkout.js"></script> in the Index.html is it possible to add somehow URL for this JS-file in the package.json file (it is simple JS-file, not NPM package; and it is just URL for this JS-file, not GitHub URL) to NPM download and install it? The reason for it - there is a Webpack config which make some processing of all used JS-files. May be it is better to include all external JS-files (not NPM packages) into this Webpack processing
If you are already using Webpack you may consider using something like little-loader.
npm i little-loader --save
And then in your code
var load = require("little-loader");
load("https://checkout.stripe.com/checkout.js", function (err) {
// ... your code ...
});
You can get some more inspiration from other answers as well.
In the Webpack issues I see the maintainer suggesting this approach:
var $script = require("scriptjs");
$script("https://checkout.stripe.com/checkout.js", function() {
//.... your code ...
});
But that package looks a bit unmaintained.
At the end of the day, an option to consider is to just leave it in the HTML as well, it's not necessarily a bad thing.
I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';
I'd like to be able to install Javascript dependencies through bower and use them in a sails.js app, but I can't figure out a way to do this with out just copying an pasting files from the bower_components folder to the Sails assets folder.
Ideally I think I'd like to use requirejs and point to the bower components in the main.js file. I may be trying to pound a square peg in a round hole, please let me know if so. Any thoughts on managing components/libraries with Sails are welcome.
In Sails 0.10 the 'assets/linker' directory no longer exists, however I found a lead on simple solution that gives some automation to the bower -> asset linker workflow while also allowing some granular control over what exactly ends up getting linked.
The solution is adding grunt-bower to your Sails.js compileAssets task
grunt.registerTask('compileAssets', [
'clean:dev',
'bower:dev',
'jst:dev',
'less:dev',
'copy:dev',
'coffee:dev'
]);
Then configure your grunt-bower task like so (as tasks/config/bower.js):
module.exports = function(grunt) {
grunt.config.set('bower', {
dev: {
dest: '.tmp/public',
js_dest: '.tmp/public/js',
css_dest: '.tmp/public/styles'
}
});
grunt.loadNpmTasks('grunt-bower');
};
This will automatically copy your bower js and css files to the proper place for Sail's asset linker to find and automatically add to your project's layout template. Any other js or css files will still automatically be added after your bower files.
However this is still no silver bullet as this setup has 2 big caveats to it:
1 - The files that are added through bower-grunt have to be listed in bower.json's main array. If you see a file isn't being loaded you would expect to be, you must either edit that packages bower.json file OR add the dependency manually through grunt-bower's packageSpecific options.
2 - The order of bower files in the asset linker is currently alphabetical. My only recourse to adjust this order so far is tinkering around with an additional grunt task to manually re-order files prior to the rest of Sail's compileAssets task. However this one I'm confident there is something grunt-bower could do by supporting package copy ordering.
Note: the following answer is no longer completely relevant to the current version of SailsJS because there is no support for the linker folder as of SailsJS 0.10.
See: Sails not generating linker
Original answer:
I was able to figure out a solution for this, which is actually pretty simple. I had not realized you could configure where bower places it's files.
Create a .bowerrc file and change the directory where bower components are installed, in the case of Sailjs they should be put into the assets folder.
/*
* Create a file called .bowerrc and put the following in it.
* This file should be in the root directory of the sails app.
*/
{
"directory": "assets/linker/bower_components"
}
Sails will then use grunt to copy them to the .tmp/public/assets folder whenever a file is change. If you don't wish to have sails continually deleting and then recopying those files you can exclude them in the grunt file.
/*
* This is not necessary, but if you have a lot of components and don't want
* them constantly being deleted and copied at every file change you can update
* your Gruntfile.js with the below.
*/
clean: {
dev: ['.tmp/public/**',
'!.tmp/public',
'!.tmp/public/bower_components/**'],
build: ['www']
},
One tip on using requirejs with sails. By default you will get an error from the socket.io file since sails will load it without using requirejs. This will throw an error since socket.io supports amd style loading, more details here http://requirejs.org/docs/errors.html#mismatch.
The simplest way to fix this is to just comment out the lines near the end of the socket.io.js.
/*
* Comment the below out in the file assets/js/socket.io.js, if using requirejs
* and you don't want to modify the default sails setup or socket.io.
*/
if (typeof define === "function" && define.amd) {
define([], function () { return io; });
}
The other way would be to recode the sails files in assets/js named "socket.io.js", "sails.io.js" and app.js to be amd modules.
The simplest way I've found of achieving this is simply to add the individual Bower components to your tasks/pipeline.js file. For example, here's how you might add Modernizr:
// Client-side javascript files to inject in order
// (uses Grunt-style wildcard/glob/splat expressions)
var jsFilesToInject = [
// Load sails.io before everything else
'js/dependencies/sails.io.js',
// Dependencies like jQuery, or Angular are brought in here
'js/dependencies/**/*.js',
// =========================================================
// Modernizr:
'bower_components/modernizr/modernizr.js',
// =========================================================
// All of the rest of your client-side js files
// will be injected here in no particular order.
'js/**/*.js'
];
A link to bower_components/modernizr/modernizr.js then gets inserted in the <!--SCRIPTS--> placeholder in your layout template, and it also gets minified, etc, when you run sails lift --prod.
Sorry for my late.
I think include bower_components in linker it's a bad idea, because when you will lift sails, everything in it will be copied in .tmp and include in tags.
For example, if you have include Angular with bower, you will have two inclusions in your script: one for angular.js and one for angular.min.js. And having both is a mistake.
Here is my solution on my projects :
I have created a folder bower_component in my root directory.
I have added this line in my Gruntfile.js in the array files in copy:dev
{ '.tmp/public/linker/js/angular.js': './bower_components/angular/angular.js' }
And for each files I want to include, I need to manually add a new line in this array. I haven't find an another automatic solution. If someone finds a better solution... ;)
There is more than one approach to hooking up SailsJS and Bower.
A package for SailsJS that integrates Bower via a custom generator exists here:
https://www.npmjs.com/package/sails-generate-bower
There is one for Gulp as well.
I am struggling somewhat with pre-compilation of templates in Handlebars. My jQuery Mobile project is getting pretty big template-wise and I wish to pre-compile the templates I use.
However I can't seem to find a good explanation (like a step by step tutorial) of how to do this with Handlebars.
I still have my templates all inline using the script tags. I have handlebars installed using NPM. But now I am kinda lost in how to proceed.
I am guessing doing something like
handlebars -s event.handlebars > event.compiled
and somehow including the event.compiled contents? But then, how to call it.
I am calling my templates like so
var source = $('#tmpl_profile').html(),
template = Handlebars.compile(source),
context = user.profile()),
html = template(context);
Hope someone can shed some light on this for me.
So after much trial and error (which is the best way to learn it) here's the way that works for me.
First- externalize all your templates, say you have a template inside script tags like
<script id="tmpl_ownevents" type="text/templates">
{{#unless event}}
<div class="notfoundevents"><p>No events for you</p></div>
{{/unless}}
</script>
Create a new file called events.tmpl and copy/paste the template into that.
Be sure to remove the script elements themselves, this gotcha bit me in the a..
Install the Handlebars commandline script like so
npm install -g handlebars
go to the folder you have saved events.tmpl into and run
handlebars events.tmpl -f events.tmpl.js
Include the compiled javascript into your HTML after you included Handlebars.js
<script src="events.tmpl.js"></script>
Now all that is left is change your normal template code into something resembling the following
var template = Handlebars.templates['events.tmpl'], // your template minus the .js
context = events.all(), // your data
html = template(context);
And there you have it, super fast pre-compiled Handlebars templates.
Another great option for this is to use GruntJS. Once installed:
npm install grunt-contrib-handlebars --save-dev
Then inside your gruntfile.js
grunt.initConfig({
dirs: {
handlebars: 'app/handlebars'
},
watch: {
handlebars: {
files: ['<%= handlebars.compile.src %>'],
tasks: ['handlebars:compile']
}
},
handlebars: {
compile: {
src: '<%= dirs.handlebars %>/*.handlebars',
dest: '<%= dirs.handlebars %>/handlebars-templates.js'
}
}
});
grunt.loadNpmTasks('grunt-contrib-handlebars');
Then you simply type grunt watch from your console, and grunt will automatically compile all *.handlebars files into your handlebars-templates.js file.
Really rad way to work with handlebars.
Here is the way I do it:
Preparation
We will just assume all your template variables are in a variable called context:
var context = {
name: "Test Person",
...
};
Where to put your templates
Create a directory containing all your templates (we'll call it templates/)
Add your templates here, called filename.handlebars.
Your directory structure:
.
└── templates
├── another_template.handlebars
└── my_template.handelbars
Compiling your templates
First go to your root directory, then compile your templates with the npm CLI program:
handlebars templates/*.handlebars -f compiled.js
New directory structure:
.
├── compiled.js
└── templates
├── another_template.handlebars
└── my_template.handlebars
Usage
Include the compiled.js in your HTML page after you include the runtime:
<script src="handlebars.runtime.js"></script>
<script src="compiled.js"></script>
Render your templates using the global Handlebars object:
// If you used JavaScript object property conform file names
// Original filename: "my_template.handlebars"
Handlebars.templates.my_template(context)
// if you used special characters which are not allowed in JavaScript properties
// Original filename: "my-template.handlebars"
Handlebars.templates["my-template"](context)
Remarks
Note the file extension .handlebars. It is automatically stripped when compiling the templates.
Extra: if you use one of the Jetbrains IDEs together with the Handlebars/Mustache plugin you even get quite a good editor support.
Precompiling Handlebars Templates with Grunt
Assuming you have Node.js installed. If you don't, go do that.
1) Setting up Node dependencies:
In your applications root directory add a file named package.json. Paste the following into that file:
{
"devDependencies": {
"grunt-contrib-handlebars": "~0.6.0",
"grunt-contrib-watch": "~0.5.3",
"handlebars": "~1.3.0"
},
}
This JSON file tells Node what packages it needs to install. This helps to get other developers get up-and-running very quickly, as you'll see in the next step.
2) Installing Node Dependencies:
In your terminal/command prompt/powershell, cd into your projects root directory and run the following commands:
npm install grunt -g
npm install grunt-cli -g
And to install the dependencies listed in your package.json:
npm install
Now you've installed all of the node dependencies that you need. In your projects root directory, you'll see a node_modules folder.
3) Configuring Grunt:
In your projects root directory, create a file named Gruntfile.js. Paste the following into that file:
module.exports = function(grunt) {
var TEMPLATES_LOCATION = "./src/templates/", // don't forget the trailing /
TEMPLATES_EXTENSION = ".hbs",
TEMPLATES_OUTPUT_LOCATION = TEMPLATES_LOCATION, // don't forget the trailing /
TEMPLATES_OUTPUT_FILENAME = "compiled_templates.js"; // don't forget the .js
grunt.initConfig({
watch: {
handlebars: {
files: [TEMPLATES_LOCATION + '**/*' + TEMPLATES_EXTENSION],
tasks: ['handlebars:compile']
}
},
handlebars: {
compile: {
src: TEMPLATES_LOCATION + '**/*' + TEMPLATES_EXTENSION,
dest: TEMPLATES_OUTPUT_LOCATION + TEMPLATES_OUTPUT_FILENAME,
options: {
amd: true,
namespace: "templates"
}
}
}
});
grunt.loadNpmTasks('grunt-contrib-handlebars');
grunt.loadNpmTasks('grunt-contrib-watch');
}
4) Configuring to Your Liking:
If you are not using Require.js, you'll want to change handlebars.compile.options.amd to false. You may also want to tweak the namespace option to your liking. If you're using require/amd modules, the namespace property is unimportant (it's default is "JST", if you remove it).
Because all project structures are a little bit different, you'll need to configure the Gruntfile just a little bit. Modify the constants TEMPLATES_LOCATION, TEMPLATES_EXTENSION, TEMPLATES_OUTPUT_LOCATION, TEMPLATES_OUTPUT_FILENAME to fit your project.
If your templates are scattered throughout your application, you'll want to change TEMPLATES_LOCATION to the lowest directory possible. Make sure your templates are isolated from your node_modules, bower_components or any other 3rd party directories, because you don't want Grunt to compile 3rd Party templates into your applications compiled templates. If you include all of your own code in a ./src, ./js, ./app directory, you'll be okay.
5) Compiling templates with Grunt:
To run grunt in the background, open your terminal and cd into your projects root directory and run the command: grunt watch:handlebars (just grunt watch works as well). With grunt running in the background, all changes to your template files will be automatically compiled and the output file specified handlebars.compile.dest will be rewritten as needed. The output will look something like this:
Running "watch" task
Waiting...
To run the compile task alone, open your terminal and cd into your projects root directory and run the command: grunt handlebars:compile (just grunt:handlebars works as well). The output will look something like:
Running "handlebars:compile" <handlebars> task
File "./src/templates/compiled_templates.js" created.
Done, without errors.
For Handlebars 2.0.0 alpha Update:
#Macro has explained quite clearly how it works with 1 piece of template, please see this answer for how to make handlebars.js works
If you see "TypeError: 'undefined' is not a function" when using precompiled templates:
This error happened at "handlebar.runtime.js" line 436 when evaluting templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data),
because the compiler npm installed is not matching the one used by the browser. The latest stable version downloaded is v1.3.0 while if you use npm install handlebars, it will install 2.0.0-alpha4 for you.
Please check it out using
handlebars any_your_template_before_compile.handlebars | grep "compiler"
which will give you like, if you indeed installed handlebar 2.0.0-alpha4:
this.compiler = [5, '>=2.0.0']
With the first number stands for the version for your handlebar compiler. Type in the following code in browser console, see if the result match the version.
Handlebars.COMPILER_REVISION
If you have compiler 5 with browser revison 4, then you will have the above problem.
To fix it, install handlebar 1.3.0 with the following command
npm install handlebars#1.3.0 -g
Then try to compile it again, you will see this time, it gives you matching version info and you are good to go with the precompiled templates.
this.compilerInfo = [4, '>=1.0.0']
Just explain if you have tons of templates:
Firstly externalize each piece of your braced templates: event.handlebars, item.handlebars, etc... You can put them all in one folder, say "/templates"
Compile all the files and concatenate it into 1 file with the following command:
handlebars *.handlebars -f templates.js
And include handlebars.runtime, this file in your HTML
<script src="/lib/handlebars.runtime.js"></script>
<script src="templates.js"></script>
The templates will be injected into Handlebars.templates by their name. For example, event.handlebars can be accessed by Handlebars.tempaltes['event'].