meteor one time initialization code on client side - javascript

Related: Where to include Client-side Startup Code in Meteor React App
Similar issue here.
I want to do some imports from the server and also some initalization once on the client (the sooner the better).
Right now i have my code included in a template:
import { foo } from "../../imports/api/foo/foo.js";
Template.header.events({
//init foo - should be called once and moved elsewehre
...
//use foo
});
But yeah ofc it's stupid because everytime the event is triggered the code gets called again.
On serverside i just used Meteor.startup for these things.
My Folder structure looks like this:
/config
/models
/packages
/client/components //current code is here
/client/config
/client/lib
/imports/api
/imports/ui
/server/lib
/server/publications
i heard that in previous meteor versions there were some folders for isomorphic code like a /lib folder but it seems like in meteor (1.3.5) the server and client code is split.
So where is a good place to do some initializations on the client side?

Actually, it doesn't matter where do you place your startup code as long as you're calling it from your client/main.js.
I'd recommend to follow Meteor's guide and proposed folder structure: Example directory layout, Structuring imports and Startup files

Related

How to use browser-side JavaScript (document, window, etc.) when running a node.js server to change the HTML document?

here's my situation. I just started learning about node.js server with express and I find it to be an amazing technology, based on JavaScript that I am already a bit familiar with.
Now, so far, whenever I want to change something on the page, I have to do it with JS on the server-side with node.js, and thus, I have to refresh the page with new information. But in several cases this seems to be not the best way to handle things, like changing simple text contents or click events. I would like to use browser-side JS for that reason, but I have not found out a way to do that yet.
I tried to call js-files and import them, but I couldn't make it work.
<script src="../../public/js/index.js"></script>
I also put the index.js and functional.js in the public folder, which I have made available to node.js at all times, but the imported JS still cannot be found when the project is run on the server.
app.use(express.static('public'));
app.use(express.static(path.join(__dirname, '/public')));
The strange thing is, I have been looking all over the internet on trying to find an explanation to it for several days already, but I couldn't find anything that made it clear to me on how to use browser-JS with a node.js server.
My folder structure is this:
functional.js
exports.functional = () => {
alert("Do something...");
}
index.js
const { functional } = require('./functional');
document.addEventListener('DOMContentLoaded', () => {
const init = (() => {
functional();
})();
});
So now I have the following questions:
Can browser-side JS even be used with a node.js server?
If it can be used, how do I implement those js-files, so they actually work?
Every help is greatly appreciated!
Thanks :)
Static Folder
You're defining a static folder in Express, here.
app.use(express.static('public'));
This tells Express that every static file (css, js, images, .etc) are found in the folder public. Now Express handles this smart and now knows that when you're looking for a static file, it is in that folder you've specified.
<script src="js/index.js"></script>
This will look into the folder public for the folder js and the file index.js. public/js/index.js.
Modules
The script itself needs some modification. Node.js uses a module system called CommonJS. And the syntax works works like in your file exports.functional, require('./functional'). But that is a technology that only works on the Node.js environment. Not in the browser.
JavaScript does also have a native module system, which is also available in Node.js, which works with the import and export keywords.
export const functional = () => {
alert("Do something...");
};
import { functional } from './functional' ;
document.addEventListener('DOMContentLoaded', () => {
functional();
});
But wait
By using the native module system on the client side, you'll need to load all the scripts that have exported and imported values in them, otherwise you'd be missing pieces.
<script type="module" src="js/functional.js"></script>
<script type="module" src="js/index.js"></script>
Bundler
The mainstream use of import and export modules is in combination with a module bundler like Webpack, which combines all the modules into a single file, which you can serve to the browser. This is very useful for development to keep the files you work in small.
It can transform the following files from this:
public
-- dist <-- bundled files ready for distribution
-- src <-- raw source files to work with
---- js
------ index.js
------ functional.js
to this:
public
-- dist <-- bundled files ready for distribution
---- js
------ bundle.js <-- Single file ready for the browser
-- src <-- raw source files to work with
---- js
------ index.js
------ functional.js
The bundler program also works on the Node.js environment, just like Express.js, so you can include it in your project.
Alternative
If the bundlers seem like a huge hassle, then you could always choose to classically use a single file to serve your JavaScript in.
on what you did:
<script src="../../public/js/index.js"></script
you are trying to call index.js relative to your node file (correct me if i'm wrong)
its a mistake because this is what express.static does
just try:
<script src="js/index.js"></script>
beacuse you already told node to take all files from that location
so instead calling files relative to your node file you need to call it from public folder
hope i helped you

Using imports, how does the server com with the client?

I'm confused by how we import [Publish] functions and [Meteor Methods] that reside under /imports/server to the Blaze client (either in /imports/client/ui or even just under app-name/client).
The classic way, is to just use the publish or meteor method, and everything is consumed by the client without imports. But if everything resides under the /imports directory (including the Blaze templates) how does that work? Are there real examples out there?
Illustration:
// imports/server/publishing/test.js
Meteor.publish('publish.test', function() {
if (this.userId) return TestCollection.find({});
return self.ready();
});
// imports/client/ui/test.js
import { Template } from "meteor/templating";
import { ReactiveDict } from "meteor/reactive-dict";
import { Mongo } from 'meteor/mongo';
import TestCollection from '../../imports/collections/test.js';
import "./test.html";
Template.Test.onCreated(function() {
this.state = new ReactiveDict();
this.autorun(() => {
const subscription = this.subscribe('publish.test');
...
}
});
});
How do server side only stuff make its way to the client in the new imports syle of developing?
UPDATE1:
Reponding to Answer1, would something like this work? Also, does the client look okay?
// app-name/imports/server/trades-pubs.js
// This code only runs on the server
Meteor.publish('trades', function tradesPublication() {
return Trades.find({},{sort: {timestamp: -1}, limit: 1000});
});
// app-name/imports/server/trades-methods.js
Meteor.methods({
// Only on server
'trades.importFromFiles'() {
fs = require('fs');
const path = "/home/daemmon/trades_data/";
var files = fs.readdirSync(path);
...
}
});
// app-name/server/main.js
import '../imports/server/trades-methods.js';
import '../imports/server/trades-pubs.js';
Is this all that's needed to get a publish methods to the client and server side meteor methods avaialbe to the client?
// imports/client/ui/test.js
import { Template } from "meteor/templating";
import { ReactiveDict } from "meteor/reactive-dict";
import { Mongo } from 'meteor/mongo';
import TestCollection from '../../imports/collections/test.js';
import "./test.html";
Template.Test.onCreated(function() {
this.state = new ReactiveDict();
this.autorun(() => {
const subscription = this.subscribe('trades');
...
}
});
});
UPDATE2:
you might want to consider importing app-name/imports/server/trades-methods.js somewhere in your client code as well, i.e. in a file like app-name/client/main.js
I thought we could not import server code on the client? If I wanted to import trades-methods.js for example, I'd have to move it to app-name/imports/api or something outside /imports/server.
UPDATE3:
Reading the Meteor Guide, I'm confused by this paragraph:
.
To fully use the module system and ensure that our code only runs when we ask it to, we recommend that all of your application code should be placed inside the imports/ directory. This means that the Meteor build system will only bundle and include that file if it is referenced from another file using an import (also called “lazy evaluation or loading”).
Meteor will load all files outside of any directory named imports/ in the application using the default file load order rules (also called “eager evaluation or loading”). It is recommended that you create exactly two eagerly loaded files, client/main.js and server/main.js, in order to define explicit entry points for both the client and the server. Meteor ensures that any file in any directory named server/ will only be available on the server, and likewise for files in any directory named client/. This also precludes trying to import a file to be used on the server from any directory named client/ even if it is nested in an imports/ directory and vice versa for importing client files from server/.
These main.js files won’t do anything themselves, but they should import some startup modules which will run immediately, on client and server respectively, when the app loads. These modules should do any configuration necessary for the packages you are using in your app, and import the rest of your app’s code.
.
Doesn't this mean for example that if there is a file inside the [/app-name/imports/server] directory, this file can NOT be imported in the client here [/app-name/client/main.js]?
.
For example I could NOT do the following:
Module inside the imports /server directory:
/app-name/imports/server/server-test.js
Module inside the imports /client directory:
/app-name/imports/client/client-test.js
.
Entry point in Meteor client:
/app-name/client/main.js
// => Would NOT work?
import { ServerTest } from "../../imports/server/server-test.js";
// => Would work?
import { ClientTest } from "../../imports/client/client-test.js";
UPDATE4:
Your wording here on your Update2:
Within the /imports folder, there are no special folder names - so you
can import a file from /imports/server in your client side code.
... is incorrect according to the author of this portion of the Meteor Guide.
First of all, since publications and methods are referenced only by their string name, they don't need to be imported in the code that subscribes to them or calls the functions. When doing Meteor.subscribe('publication') Meteor will try to find a publication named publication in the server, and subscribe to it. Same works with Meteor methods.
However, when using the /imports folder, your publications and methods need to be imported somewhere in server code so that Meteor loads them at all. The best practice to do this is to place a file somewhere in the imports folder, like /imports/startup/server/index.js (as recommended by the Meteor guide), where you simply import all files that declare publications and methods, and then importing this single file in some file outside the imports folder. For more about this, see the Meteor Guide and its example app.
Note also that for Meteor methods, you may want to include them also somewhere in your client code, so that the client can run simulations of them for optimistic UI before the server call returns. To do this, you can do the same as above but with a file like /imports/startup/client/index.js, that you include in the client code. I also recommend checking out the mdg:validated-method package, it makes using methods cleaner.
Update regarding the update in the question:
Yes, that seems like it would work, I think you got the point :)
As a minor detail, as I said, you might want to consider importing app-name/imports/server/trades-methods.js somewhere in your client code as well, i.e. in a file like app-name/client/main.js. This would enable the client to run a simulation of the method and update the UI immediately for better user experience. Don't do this if you don't want to expose some super-secret server code to the client though.
Update 2 in the question
Within the /imports folder, there are no special folder names - so you can import a file from /imports/server in your client side code. However, I do recommend placing code that is only meant for the server, like publications, in a folder named server, and not placing code that is meant to be used from both sides to a folder named server or client. Thus you might want to move your trades-methods.js file outside your /imports/server folder anyway. However this is only for clarity, Meteor does not care about folder names inside /server!
I really, really recommend you to read the Meteor guide, particularly the chapter on application structure and checking out the structure of the related example app. You'll save so much time in the long run!

Project structure in meteor and problems with import

I am new to meteor and i use it to create a webgl application for mobile devices.
My problem is the file structure. I already read the manuals so pls dont link to them.
1.The lib gets loaded first , so i put all my code that should be executed in main.js there?(i.g. for my webgl project i use a lot of oop, so does it make sense to put my code here?)
2.Consider the following structure
Everything i use for the webgl application is in the src folder, but if i want to Application.run(); i always get the error Uncaught Error: Cannot find module 'src/Application.js'. This problem occurs in every folder i put the src folder in, wether it is lib or import or whatever.
My Application.js looks like this:
var Application={};
Application.run = function () {
//code
}
module.exports = Application;
But what i really want for Application.js is:
function Application(){
//some stuff
}
Application.prototype.run = function(){
//some stuff
}
So how can i use the second approach of application.js in main.js AND if its not possible how should i do it instead?
From your screenshot, it looks like your Application.js file is actually named just Application (without the .js extension).
That may be the reason why your project does not find 'src/Application.js'.

How can I use Gulp and Browserify for my javascript app?

I am finally trying to bring a modern build system to my app, and I'm hoping someone can help. I think I need a few paradigm shifts.
So this is how my app is structured:
/src
/components
/Base
/App.jsx
/Pages.jsx
/...
/Page1
/Page1Component1.jsx
/Page1Component2.jsx
/...
/Page2
/Page2Component1.jsx
/Page2Component2.jsx
/...
/...
/libs
/bootstrap.js
/jquery.js
/react.js
/...
/scripts
/index.js
/utils.js
/styles
/main.css
/html
/index.html
Right now I have gulp set up to do this:
Make a new folder /dest to put everything
Combine everything in /scripts, name it main.js, put it in dest
Combine everything in /libs, name it libs.js, put it in dest
Combine everything in /components, run it through babel, name it comps.js, put it in dest
Copy the one /html file and one /styles file into dest
Then here is how the app runs:
Open index.html
That page requests main.js
main.js requests libs.js and comps.js
Everything works
But here is the issue I'm running into: A lot of stuff here relies on other stuff being global. index.js waits for comps.js and libs.js to load, then calls ReactDOM.render(<App />...), which means both ReactDOM and App need to be global.
Now I'm trying to add something that needs require(), and I try to use Browserify for it. But Browserify takes the code that needs the require and wraps it up in a way that, I believe, makes nothing global.
I realize that I need to turn my app into actual modules, instead of just a bunch of files that concatenate and call each other. And I know that avoiding global variables will be a good thing in the long run. But I'm having a really hard time figuring out how.
For example, I have >50 React modules. It seems wrong to add module.exports to every single one of those, and then import them all to the main file. Further, some of the things in /lib are libraries that don't export as modules, they're made to be run in the <head> tag, like Google Charts.
So I guess my questions are:
Where should my module exports be, and how do they fit into my gulp tasks? Do I concatenate then export?
How do I deal with libraries that aren't modules?
Is my app really poorly laid out, and I just need to restructure from scratch?
Thanks, and sorry about the rambley question.
First, there's nothing wrong with your file structure.
Second, the best thing you can do is follow the "one module, one file" rule. That does mean adding module.exports or export default to every single file. That's just good JavaScript. But it doesn't mean importing them all into your main file, which brings us to:
Third, think in modularity. Files should require or import precisely what they need and nothing they don't. For example, if your App uses Page1 and Page1 uses Page1Component1, then that's how your imports should work:
App -> Page1 -> Page1Component1
-> Page1Component2
-> Page2 -> Page2Component1
-> ...
This ensure separation of concerns and protects your code from easy-to-trigger errors later on (like those from nested dependency changes). And your build system should generate one file (but you can tackle performance later if needed with chunking and so forth).
And you're correct that in this kind of structure, using Browserify or Webpack will ensure that nothing is global - and that's a good thing (though I will note that you can tell them explicitly to expose components, which is sometimes necessary for libraries).
And that leaves libraries that you don't control that you can't import. This does not apply to Bootstrap, jQuery, or React, which all have require-able modules from NPM. But assuming that you have a library you didn't mention that is not available through NPM, you can still include it globally in your HTML with a script tag and tell Browserify or Webpack to expose it for requiring.

I need a strongloop example wrote in javascript without angular

I want to have a strongloop example only using javascript without angular.
There's no complete working example without angular for now.
I want to simply include the browser.bundle.js in my index.html, then sync data from/to server side. In fact, I'm trying to replace pouchdb in my program since the couchdb seems not success in open source community.
I can't follow up this document correctly:
Running Loopback in the browser
create browser-app.js with the content from Running Loopback in the browser
copy past the content to browser-app.js
npm install loopback loopback-boot
browserify browser-app.js -o app.bundle.js Then I got error: Error: Cannot find module 'loopback-boot#instructions' from '/Users/simba/Projects/traveller-app/client/node_modules/loopback-boot'
There are few steps for this but its pretty simple.
Bootstrap your application via slc loopback.
Delete server/boot/root.js.
Uncomment two lines in server/server.js, it should look like:
...
// -- Mount static files here--
// All static middleware should be registered at the end, as all requests
// passing the static middleware are hitting the file system
// Example:
var path = require('path'); //this line is now uncommented
app.use(loopback.static(path.resolve(__dirname, '../client'))); //this line is now uncommented
...
Create index.html in the client dir (ie. client/index.html) with your contents.
That should get you a basic set up with just a basic front-end working. Let me know if you have any more issues.

Categories