I've created an ember app with yeoman and am trying to get the build to order the scripts. I have an app.coffee which contains require 'scripts/controllers/*' but I also need to order the scripts within controllers. I have something like this:
controllers/foo_controller.js.coffee
require "./bar_controller"
App.FooController = App.BarController.extend()
controllers/bar_controller.js.coffee
App.BarController = Ember.Controller.extend()
But it isn't ordering these files. Am I doing it correctly?
I fixed this, I had the relative path wrong. It should have looked like this:
require "scripts/controllers/bar_controller"
App.FooController = App.BarController.extend()
Related
I have the map+tilemap project created in a 3rd-party app. The whole project is a set of files, the main file (XML) representing the 2D game level map and some other files (subfiles) representing graphics and tilemaps.
I am trying to create a Webpack Loader that will compile and convert the whole map/tilemap project into JSON object, that is comfortable to use in javascript. And I still can't get how to:
How can I access subfiles (taken from relative paths from the main file), what is the way to access the current directory (where the main file is placed), and the name of the main file?
How can I explain to Webpack to track changes in all subfiles, so it will run the loader again automatically to compile the whole map/tilemap project (partial re-packing).
I spent 2 days to find any working solutions, it is possible at all?
Thanks a lot!
For the first question, webpack loader is expose the file info by this, you can do like this:
module.exports = function (source) {
const loaderContext = this;
const { sourceMap, rootContext, resourcePath } = loaderContext;
const sourceRoot = path.dirname(path.relative(context, resourcePath));
...
}
For the second question, i think that maybe you can use the module.hot to track the subfiles change, like this:
if (module.hot) {
module.hot.accept('filepath', ()=>{
...
})
}
I struggle to properly configure and set up my own JS files that contain JS functions for specific tasks.
I went through some articles and found that I need to place my custom JS to the JS packs folder -> app/javascript/packs/currency_calculations.js:
currency_calculations.js:
function convert_curr(from, to) {
...
}
function show_convertion(curr) {
...
}
...
and then I try to add this custom JS file to app/javascript/packs/application.js:
import Rails from "#rails/ujs";
import "#hotwired/turbo-rails";
import * as ActiveStorage from "#rails/activestorage";
import "channels";
import "controllers";
Rails.start();
ActiveStorage.start();
import "stylesheets/application";
// my custom JS file
import "packs/currency_calculations" // I also tried import "currency_calculations" -- same result
I also tried to add the following to the application.html.erb file:
= javascript_pack_tag 'currency_calculations'
It didn't work either.
I am still getting this error:
Uncaught Error: Cannot find module 'currency_calculations'
and when trying to call a function from a view, then:
Uncaught ReferenceError: convert_curr is not defined
What is the correct way to wire this up? I am used from Rails 5 to put all my JS functions to a js file and this file just to add to a app/assets/javascripts/application.js like this:
//= require currency_calculations
and then, in a view, I am able to simply call the wanted JS function like convert_curr("a", "b").
Thank you in advance.
There's a couple of ways to do this in Rails 6.
The first would be to create a custom directory and require it in the application.js file. In this case you could create a directory like this:
app/javascript/custom/currency_calculations.js
Then you would need to require it in your application.js file as such:
// app/javascript/packs/application.js
// ...
require("#rails/ujs").start()
require("turbolinks").start()
require("#rails/activestorage").start()
require("channels")
require("custom/currency_calculations")
That same method could also be streamlined if you, say, named your custom folder "currency" and then named the .js file index.js.
You could then just call it like this:
require("currency")
Require will look for the index file by default in the folder. But in that scenario, an index file must be present, or it will fail.
The other way to do this, in the event you don't want that JS to be compiled with everything else, is to use the javascript_pack_tag.
In that case, add the js file to your app/javascript/packs directory. Then use the pack tag helper where you need it such as:
<%= javascript_pack_tag 'currency_converter' %>
The last thing I would mention... are you sure there's no other library needed to make it work (such as JQuery)? In that case you would need to install and import that library to your application.js before you called the js file you're trying to execute.
I think the problem is you are not exporting anything in your js file. Try doing this in currency_calculations.js
const funcs = {
convert_curr() { console.log('foo') },
show_convertion() { console.log('bar') },
}
export default funcs;
And then in your code you call them with funcs.convert_curr()
Also it seems that currency_calculation shouldn't be it's own pack (you can think of a pack kinda like what application.js was in sprockets), so better be just a standalone js file outside the packs dir. (could be javascript/currency_calculations.js or javascript/utils/currency_calculations.js)
Some comments that may help you:
1 ) when you put a js file at /packs, it's going to be compiled as a standalone asset you can reference using javascript_pack_tag, so you don't need to add it to the application.js pack
you have two options depending on what you want:
move the file to javascript/src/currency_calculations.js and import it in your application.js as import 'src/currency_calculations' or import '../src/currency_calculations'
use it as a pack, remove it from application.js and use load it like javascript_pack_tag 'currency_calculations'
(you can have the file loaded both in application.js and as a standalone pack, but you'll have the code twice)
2 ) if you want to access the functions from that file in your view, you can't do it just like sprocket does. sprockets adds the content of that file in the global scope while webpacker contains the functions in the bundle context. If you want the functions to be available globally from your views, you have to make them global doing something like
global.convert_curr = function(from, to) {
...
}
(you can also use window.convert_curr = ...)
I have generated my app with express --view=pug myapp which created me a folder-tree with the files I need to start over.. I wrote some code which I would like to outsource from the main app.js in maybe a function-file or something like that, to keep the app.js cleaner.
where would I put my custom functions? how would I then require the function-file in nodeJS ?
You can arrange your files as you wish. Wherever you keep your functions, just add the functions you want to use in any other files to module.exports object in that file. Then in your app.js (or any other file where you want to use these functions), import the file using require and you should have access to all the exported properties and functions from the file you import.
For example:
I can put my functions in ./lib/core-lib.js:
function test(){
// do something
}
module.exports = {
test: test
};
And then in my app.js
const lib = require('./lib/core-lib');
lib.test();
I am working on a Ruby/React project. We are using React components and CoffeeScript and final JS is assembled by Sprockets:
#= require org/components/whatever
{ Whatever } = Org.Components
It is okay when there is not too much nesting and then you are wrtiting something like this:
#= require org/components/whatever
#= require org/components/something/else/whatever
{ Whatever1 } = Org.Components
{ Whatever2 } = Org.Components.Something.Else
Today I was trying to find where Org.Components.Image.Upload is used. But sometimes it is imported as { Upload } or used as Image.Upload and it doesn't make things easier.
Now I am thinking maybe don't go further than Org.Components for imports. So if you need Image.Upload — get { Image } = Org.Components, and use Image.Upload. If it gets too long - assign to a variable.
#= require org/components/image
{Image} = Org.Components
Upload = Image.Super.Complex.Upload
# Or use it like this for explicitness
render: ->
Image.Super.Complex.Upload
What is the best practice here? I want code to be searchable.
If you are in a CommonJS environment (Node), and probably using a module bundler like Webpack or Browserify you can take advantage of the direct module imports. For example:
Instead of doing this Org.Components.Image, you can do that:
import Upload from 'org/components/Image/Super/Complex/Upload'
// or var Image = require('org/components/Image/Super/Complex/Upload');
In your original strategy you load the entire library (org) to further filter it down to Upload.
In the proposed solution above, you only load the Image module and nothing else. This will probably save you a lot of bits in your final footprint, specially if org contains a big pile of components used inside your company.
To stop fighting against the sprockets I have defined a Root component that tells Sprockets where to look for the subcomponents:
# components/branding.coffee
#= require_tree ./branding
Org.Components.Branding = {}
So now if I need anything from the branding subtree I simply do the following:
#= require org/components/branding
{div} = React.DOM
{Branding} = Org.Components
Org.defineComponent "Settings.Branding",
render: ->
div {},
Branding.Edit.ContactUs {}
Branding.Config {},
Branding.Edit
This way I don't need to worry about dependencies and found it to be much more pleasant to work with.
I would suggest that this approach helps refactoring as you don't have to change multiple requires everywhere.
Branding.Config is a data-wrapped that loads and syncs settings. In the example above it is used to load settings for the Brading.Edit page. And here it is loading branding for in 'Layouts.Default'.
And again I only require branding
# apps/src/org/components/layouts/default.coffee
#= require org/components/branding
{Branding, TenantStateBar, UnsupportedBrowserBar} = Org.Components
Org.defineComponent 'Layouts.Default',
render: ->
div {},
Branding.Config {},
Branding.Style
I have a marionette project, and I have my main js file which looks like:
define(["marionette", "handlebars"], function(Marionette, Handlebars){
...
});
Now I want to make a structure of my big app. So I would like to separate the content of this function to different files. So how can I do something like:
define(["marionette", "handlebars"], function(Marionette, Handlebars){
include routes.js
include menu/model.js
include menu/views.js
...
});
I think require.js can help me, but I don't know how. Any ideas?
To require a file in the AMD structure (like the one you describe), you can give the path to the file in the array and get the exported value as argument of the callback like this.
define(
[
"marionette",
"handlebars",
"routes",
"menu/model",
"menu/views"
],
function(Marionette, Handlebars, Routes, Model, MenuView){
// ...
});
Since this is a very basic thing in AMD, you should really read the documentation of Require.JS (here) and explanation about AMD modules (like this one). You will find lot of information about the AMD structure, etc
If you prefer, browserify lets you to load front-end javascript modules using the require syntax. It looks like this.
// library includes
var Marionette = require('backbone.marionette');
var handlebars = require('handlebars');
// custom includes
var routes = require('./routes.js');
var models = require('./menu/models.js');
var views = require('./menu/views.js');
var App = new Marionette.Application();
It includes modules recursively and there is less code. It implements the Common.js format so it looks and feels the same as node.js.