display /var/log/messages in html/php output? - linux

I am trying to display the output of /var/log/messages or similar (../secure for instance) in a webpage that I access through a webserver on the same host.
Should I use bash to tail -f >> the messages file to a new output file and display that text file in the html page, or is there a better way to do this?
Thanks!
idiglivemusic

If you're looking for a way to display actual file contents online without the need to reload the page, then you should setup a WebSocket server.
You can build a WebSocket server using a framework such as phpDaemon, ReactPHP, Ratchet, icicle, or implement your own server with the help of PHP extensions wrapping asynchronous libraries: event, ev, or similar.
I've chosen a random framework from the list above: Ratchet. Ratchet is based on ReactPHP. ReactPHP chooses a backend for the event loop from the following list:
- libevent extension,
- libev extension,
- event extension,
- or an internal class based on the built-in stream_select() function.
As a maintainer of the event extension, I've chosen event.
I've written a "quick" example just to give you idea of how it might be implemented. You'll most likely have to work out your own version, maybe using different tools. But the code should give you an impulse.
src/MyApp/Server.php
<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class Server implements MessageComponentInterface {
protected $clients;
public function __construct() {
$this->clients = new \SplObjectStorage;
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection! ({$conn->resourceId})\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
$numRecv = count($this->clients) - 1;
printf("Connection %d sending '%s' to %d other connection%s\n",
$from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');
foreach ($this->clients as $client) {
if ($from !== $client) {
$client->send($msg);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
echo "Connection {$conn->resourceId} has disconnected\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "An error has occurred: {$e->getMessage()}\n";
$conn->close();
}
public function broadcast($msg) {
foreach ($this->clients as $client) {
$client->send($msg);
}
}
}
server.php
<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Server;
require __DIR__ . '/vendor/autoload.php';
$server = IoServer::factory(
new HttpServer(
new WsServer(
$my_app_server = new Server()
)
),
9989
);
$loop = $server->loop;
$filename = '/var/log/messages';
$loop->addPeriodicTimer(5, function ()
use ($filename, $my_app_server)
{
static $stat_info;
if ($stat_info == null) {
clearstatcache(true, $filename);
$stat_info = stat($filename);
}
clearstatcache(true, $filename);
$st = stat($filename);
$size_diff = $st['size'] - $stat_info['size'];
echo "Diff = $size_diff bytes\n";
if ($size_diff > 0) {
$offset = $stat_info['size'];
$bytes = $size_diff;
} elseif ($size_diff < 0) {
// The file is likely truncated by `logrotate` or similar utility
$offset = 0;
$bytes = $st['size'];
} else {
$bytes = 0;
}
$stat_info = $st;
if ($bytes) {
if (! $fp = fopen($filename, 'r')) {
fprintf(STDERR, "Failed to open file $filename\n");
return;
}
if ($offset > 0) {
fseek($fp, $offset);
}
if ($msg = fread($fp, $bytes)) {
$my_app_server->broadcast($msg);
}
fclose($fp);
}
}
);
$server->run();
test.html
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>Test</title>
</head>
<body>
<script>
var conn = new WebSocket('ws://localhost:9989');
conn.onopen = function(e) {
console.log("Connection established!");
};
conn.onmessage = function(e) {
console.log("Msg from server", e.data);
};
</script>
</body>
</html>
I'll skip the steps required to setup a basic test environment using Composer. Assuming you have successfully configured the test environment for the files above, you'll be able to run the server with the following command:
php server.php
Check, if the user has permissions to read /var/log/messages. On my system only root can read the file. So you might need to run the above-mentioned command with sudo(root permissions).
Now you can open test.html in a browser and look at the console output. Then trigger some event which is normally logged to the messages file. For instance, you can invoke sudo with a wrong password. The server should detect the changes within interval of 5 seconds, then send it to the WebSocket clients.

If you're using tail -f, that means that you'll be continuously getting data from the file while it grows as the command runs.
You can use cat or tail -n. Also, of course, you can access files directly by creating a symbolic or hard link to them (ln source-file link-file, ln -s source-file link-file) - but make sure, that your web-server has enough rights to access them.

Make sure that your html-server has rights to access the page and read the page (with something like cat, tail, grep).
In <html> put the output between <pre> and </pre>.

Method 1
In one of your base directories, create a symbolic link
ln -s /var/log/messages messages
If the directory belonged to say, test.web, access the log with
unmesh
http://test.web/messages
Method 2
If you're looking for a php script then, first create the link as mentioned in method 1. Then, create a new file, say, readlog.php in the base directory of test.web with the below content :
<?php
readfile(“$DOCUMENT_ROOT/messages”);
?>
Access the readlog.php like :
http://test.web/readlog.php
Requirement:
Read access should be enabled for all users for /var/log/messages.
Note:
Setting read option for /var/log/messages for the whole world is NOT a good idea.

<!DOCTYPE html>
<html>
<head>
<title>toyLogs</title>
</head>
<body>
<div><p><?php include('/var/www/html/accesslog.txt'); ?></p></div>
</body>
</html>

Related

How can I run a Go WASM program using Node.js?

I created a test WASM program using Go. In the program's main, it adds an API to the "global" and waits on a channel to avoid from exiting. It is similar to the typical hello-world Go WASM that you can find anywhere in the internet.
My test WASM program works well in Browsers, however, I hope to run it and call the API using Node.js. If it is possible, I will create some automation tests based on it.
I tried many ways but I just couldn't get it work with Node.js. The problem is that, in Node.js, the API cannot be found in the "global". How can I run a GO WASM program (with an exported API) in Node.js?
(Let me know if you need more details)
Thanks!
More details:
--- On Go's side (pseudo code) ---
func main() {
fmt.Println("My Web Assembly")
js.Global().Set("myEcho", myEcho())
<-make(chan bool)
}
func myEcho() js.Func {
return js.FuncOf(func(this js.Value, apiArgs []js.Value) any {
for arg := range(apiArgs) {
fmt.Println(arg.String())
}
}
}
// build: GOOS=js GOARCH=wasm go build -o myecho.wasm path/to/the/package
--- On browser's side ---
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<p><pre style="font-family:courier;" id="my-canvas"/></p>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("myecho.wasm"), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
// it also works without "window."
document.getElementById("my-canvas").innerHTML = window.myEcho("hello", "ahoj", "ciao");
})
})
</script>
</body>
</html>
--- On Node.js' side ---
globalThis.require = require;
globalThis.fs = require("fs");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;
globalThis.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};
const crypto = require("crypto");
globalThis.crypto = {
getRandomValues(b) {
crypto.randomFillSync(b);
},
};
require("./wasm_exec");
const go = new Go();
go.argv = process.argv.slice(2);
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
console.log(go.exports.myEcho("hello", "ahoj", "ciao"));
}).catch((err) => {
console.error(err);
process.exit(1);
});
This pseudo code represents 99% content of my real code (only removed business related details). The problem is that I not only need to run the wasm program (myecho.wasm) by Node.js, but I also need to call the "api" (myEcho), and I need to pass it parameters and receive the returned values, because I want to create automation tests for those "api"s. With Node.js, I can launch the test js scripts and validate the outputs all in the command line environment. The browser isn't a handy tool for this case.
Running the program by node wasm_exec.js myecho.wasm isn't enough for my case.
It would be nice to know more details about your environment and what are you actually trying to do. You can post the code itself, compilation commands, and versions for all the tools involved.
Trying to answer the question without these details:
Go WASM is very browser oriented, because the go compiler needs the glue js in wasm_exec.js to run. Nodejs shouldn't have a problem with that, and the following command should work:
node wasm_exec.js main.wasm
where wasm_exec.js is the glue code shipped with your go distribution, usually found at $(go env GOROOT)/misc/wasm/wasm_exec.js, and main.wasm is your compiled code. If this fails, you can post the output as well.
There is another way to compile go code to wasm that bypasses wasm_exec.js, and that way is by using the TinyGo compiler to output wasi-enabled code. You can try following their instructions to compile your code.
For example:
tinygo build -target=wasi -o main.wasm main.go
You can build for example a javascript file wasi.js:
"use strict";
const fs = require("fs");
const { WASI } = require("wasi");
const wasi = new WASI();
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
(async () => {
const wasm = await WebAssembly.compile(
fs.readFileSync("./main.wasm")
);
const instance = await WebAssembly.instantiate(wasm, importObject);
wasi.start(instance);
})();
Recent versions of node have experimental wasi support:
node --experimental-wasi-unstable-preview1 wasi.js
These are usually the things you would try with Go and WASM, but without further details, it is hard to tell what exactly is not working.
After some struggling, I noticed that the reason is simpler than I expected.
I couldn't get the exported API function in Node.js simply because the API has not been exported yet when I tried to call them!
When the wasm program is loaded and started, it runs in parallel with the caller program (the js running in Node).
WebAssembly.instantiate(...).then(...go.run(result.instance)...).then(/*HERE!*/)
The code at "HERE" is executed too early and the main() of the wasm program hasn't finished exporting the APIs yet.
When I changed the Node script to following, it worked:
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
go.run(result.instance);
}).then(_ => {
let retry = setInterval(function () {
if (typeof(go.exports.myEcho) != "function") {
return;
}
console.log(go.exports.myEcho("hello", "ahoj", "ciao"));
clearInterval(retry);
}, 500);
}).catch((err) => {
console.error(err);
process.exit(1);
});
(only includes the changed part)
I know it doesn't seem to be a perfect solution, but at least it proved my guess about the root cause to be true.
But... why it didn't happen in browser? sigh...

how to upload a file in vibe.d using the web framework

I am still new to Vibe.d so forgive me if I am missing something obvious.
I want to upload a file in Vibe.d using the web framework. However, all the examples I find, including the one in the book 'D Web Development', are not using the web framework. If I insert the non-web-framework example to my app, it crashes. It would suck if I have to abandon the web framework just for the sake of one feature, which is file upload.
The Vibe.d documentation is a good effort and I appreciate it but until now it is rather sparse and the examples are few and far between.
Here are some snippets of my code:
shared static this()
{
auto router = new URLRouter;
router.post("/upload", &upload);
router.registerWebInterface(new WebApp);
//router.get("/", staticRedirect("/index.html"));
//router.get("/ws", handleWebSockets(&handleWebSocketConnection));
router.get("*", serveStaticFiles("public/"));
auto settings = new HTTPServerSettings;
settings.port = 8080;
settings.bindAddresses = ["::1", "127.0.0.1"];
listenHTTP(settings, router);
conn = connectMongoDB("127.0.0.1");
appStore = new WebAppStore;
}
void upload(HTTPServerRequest req, HTTPServerResponse res)
{
auto f = "filename" in req.files;
try
{
moveFile(f.tempPath, Path("./public/uploaded/images") ~ f.filename);
}
catch(Exception e)
{
copyFile(f.tempPath, Path("./public/uploaded/images") ~ f.filename);
}
res.redirect("/uploaded");
}
Can I still access the HTTPServerRequest.files using the web framework? How? Or do I still need it? Meaning, is there another way without using HTTPServerRequest.files?
Thanks a lot!
I have totally forgotten about this question. I remember how frustrating it was when you cannot readily find an answer to a question that seems to be elementary to those who already know.
Make sure you state 'multipart/form-data' in the enctype of your form:
form(method="post", action="new_employee", enctype="multipart/form-data")
Then a field in that form should include an input field of type 'file', something like this:
input(type="file", name="picture")
In the postNewEmployee() method of your web framework class, get the file through request.files:
auto pic = "picture" in request.files;
Here is a sample postNewEmployee() method being passed an Employee struct:
void postNewEmployee(Employee emp)
{
Employee e = emp;
string photopath = "No photo submitted";
auto pic = "picture" in request.files;
if(pic !is null)
{
string ext = extension(pic.filename.name);
string[] exts = [".jpg", ".jpeg", ".png", ".gif"];
if(canFind(exts, ext))
{
photopath = "uploads/photos/" ~ e.fname ~ "_" ~ e.lname ~ ext;
string dir = "./public/uploads/photos/";
mkdirRecurse(dir);
string fullpath = dir ~ e.fname ~ "_" ~ e.lname ~ ext;
try moveFile(pic.tempPath, NativePath(fullpath));
catch (Exception ex) copyFile(pic.tempPath, NativePath(fullpath));
}
}
e.photo = photopath;
empModel.addEmployee(e);
redirect("list_employees");
}
When I tried to learn Vibe.d again, I again became aware of the dearth of tutorials, so I wrote a tutorial myself while everything is fresh as a learner:
https://github.com/reyvaleza/vibed
Hope you find this useful.
Put the upload function inside the WebApp class and use it to handle the form post form(action="/upload", method ="post")
class WebApp {
addUpload(HTTPServerRequest req, ...)
{
auto file = file in req.files;
...
}
}
You can try hunt-framework, Hunt Framework is a high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design. It lets you build high-performance Web applications quickly and easily.
Sample code for action:
#Action
string upload()
{
string message;
if (request.hasFile("file1"))
{
auto file = request.file("file1");
if (file.isValid())
{
// File save path: file.path()
// Origin name: file.originalName()
// File extension: file.extension()
// File mimetype: file.mimeType()
if (file.store("uploads/myfile.zip"))
{
message = "upload is successed";
}
else
{
message = "save as error";
}
}
else
{
message = "file is not valid";
}
}
else
{
message = "not get this file";
}
return message;
}

Node webkit hotkey example not working

I'm trying to play around with node webkits hotkey example which can be viewed on their Shortcut's page here: https://github.com/nwjs/nw.js/wiki/Shortcut
Here's my code:
test.js
// Load native UI library.
var gui = window.require('nw.gui');
var option = {
key : "Ctrl+Shift+A",
active : function() {
console.log("Global desktop keyboard shortcut: " + this.key + " active.");
},
failed : function(msg) {
// :(, fail to register the |key| or couldn't parse the |key|.
console.log(msg);
}
};
// Create a shortcut with |option|.
var shortcut = new gui.Shortcut(option);
// Register global desktop shortcut, which can work without focus.
gui.App.registerGlobalHotKey(shortcut);
// If register |shortcut| successfully and user struck "Ctrl+Shift+A", |shortcut|
// will get an "active" event.
// You can also add listener to shortcut's active and failed event.
shortcut.on('active', function() {
console.log("Global desktop keyboard shortcut: " + this.key + " active.");
});
shortcut.on('failed', function(msg) {
console.log(msg);
});
// Unregister the global desktop shortcut.
gui.App.unregisterGlobalHotKey(shortcut);
index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<script>
require("./test.js");
</script>
</head>
<body>
<h1>Hello World!</h1>
We are using node.js <script>document.write(process.version)</script>.
</body>
</html>
package.json
{
"name": "nw-demo",
"main": "index.html",
"dependencies": {
"nw": "^0.12.0"
},
"scripts": {
"start": "nw"
}
}
It breaks at this line on test.js saying undefined is not a function.
var shortcut = new gui.Shortcut(option);
Just remove this line:
gui.App.unregisterGlobalHotKey(shortcut);
In your code you register it, then delete. It working well for me (mac, nwjs 0.12)
As shaynem in (https://github.com/nwjs/nw.js/issues/3263#issuecomment-89679115) points out you should be running at least node-webkit >= 0.10.0
You should make sure your PATH (or the build tool you're using, e.g. nodebob) is not referencing any old leftover versions of node-webkit after you upgrade.
Also if you're on Ubuntu, you might stumble upon an open issue (https://github.com/nwjs/nw.js/issues/3199)
note webkit 0.13.0 has a bug where the the k is lowercase even though the method is documented with an uppercase K. Try:
registerGlobalHotkey(shortcut);
to verify this bug exists do:
var util = require('util');
console.log(util.inspect(nw.App));

Browserify - How to call function bundled in a file generated through browserify in browser

I am new to nodejs and browserify. I started with this link .
I have file main.js which contains this code
var unique = require('uniq');
var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];
this.LogData =function(){
console.log(unique(data));
};
Now I Install the uniq module with npm:
npm install uniq
Then I bundle up all the required modules starting at main.js into a single file called bundle.js with the browserify command:
browserify main.js -o bundle.js
The generated file looks like this:
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var unique = require('uniq');
var data = [1, 2, 2, 3, 4, 5, 5, 5, 6];
this.LogData =function(){
console.log(unique(data));
};
},{"uniq":2}],2:[function(require,module,exports){
"use strict"
function unique_pred(list, compare) {
var ptr = 1
, len = list.length
, a=list[0], b=list[0]
for(var i=1; i<len; ++i) {
b = a
a = list[i]
if(compare(a, b)) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique_eq(list) {
var ptr = 1
, len = list.length
, a=list[0], b = list[0]
for(var i=1; i<len; ++i, b=a) {
b = a
a = list[i]
if(a !== b) {
if(i === ptr) {
ptr++
continue
}
list[ptr++] = a
}
}
list.length = ptr
return list
}
function unique(list, compare, sorted) {
if(list.length === 0) {
return []
}
if(compare) {
if(!sorted) {
list.sort(compare)
}
return unique_pred(list, compare)
}
if(!sorted) {
list.sort()
}
return unique_eq(list)
}
module.exports = unique
},{}]},{},[1])
After including bundle.js file into my index.htm page, how do I call logData function ??
The key part of bundling standalone modules with Browserify is the --s option. It exposes whatever you export from your module using node's module.exports as a global variable. The file can then be included in a <script> tag.
You only need to do this if for some reason you need that global variable to be exposed. In my case the client needed a standalone module that could be included in web pages without them needing to worry about this Browserify business.
Here's an example where we use the --s option with an argument of module:
browserify index.js --s module > dist/module.js
This will expose our module as a global variable named module.
Source.
Update:
Thanks to #fotinakis. Make sure you're passing --standalone your-module-name. If you forget that --standalone takes an argument, Browserify might silently generate an empty module since it couldn't find it.
Hope this saves you some time.
By default, browserify doesn't let you access the modules from outside of the browserified code – if you want to call code in a browserified module, you're supposed to browserify your code together with the module. See http://browserify.org/ for examples of that.
Of course, you could also explicitly make your method accessible from outside like this:
window.LogData =function(){
console.log(unique(data));
};
Then you could call LogData() from anywhere else on the page.
#Matas Vaitkevicius's answer with Browserify's standalone option is correct (#thejh's answer using the window global variable also works, but as others have noted, it pollutes the global namespace so it's not ideal). I wanted to add a little more detail on how to use the standalone option.
In the source script that you want to bundle, make sure to expose the functions you want to call via module.exports. In the client script, you can call these exposed functions via <bundle-name>.<func-name>. Here's an example:
My source file src/script.js will have this:
module.exports = {myFunc: func};
My browserify command will look something like this:
browserify src/script.js --standalone myBundle > dist/bundle.js
And my client script dist/client.js will load the bundled script
<script src="bundle.js"></script>
and then call the exposed function like this:
<script>myBundle.myFunc();</script>
There's no need to require the bundle name in the client script before calling the exposed functions, e.g. <script src="bundle.js"></script><script>var bundled = require("myBundle"); bundled.myFunc();</script> isn't necessary and won't work.
In fact, just like all functions bundled by browserify without standalone mode, the require function won't be available outside of the bundled script. Browserify allows you to use some Node functions client-side, but only in the bundled script itself; it's not meant to create a standalone module you can import and use anywhere client-side, which is why we have to go to all this extra trouble just to call a single function outside of its bundled context.
I just read through the answers and seems like nobody mentioned the use of the global variable scope? Which is usefull if you want to use the same code in node.js and in the browser.
class Test
{
constructor()
{
}
}
global.TestClass = Test;
Then you can access the TestClass anywhere.
<script src="bundle.js"></script>
<script>
var test = new TestClass(); // Enjoy!
</script>
Note: The TestClass then becomes available everywhere. Which is the same as using the window variable.
Additionally you can create a decorator that exposes a class to the global scope. Which is really nice but makes it hard to track where a variable is defined.
Read README.md of browserify about --standalone parameter
or google "browserify umd"
Minimal runnable example
This is basically the same as: https://stackoverflow.com/a/43215928/895245 but with concrete files that will allow you to just run and easily reproduce it yourself.
This code is also available at: https://github.com/cirosantilli/browserify-hello-world
index.js
const uniq = require('uniq');
function myfunc() {
return uniq([1, 2, 2, 3]).join(' ');
}
exports.myfunc = myfunc;
index.html
<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Browserify hello world</title>
</head>
<body>
<div id="container">
</body>
</div>
<script src="out.js"></script>
<script>
document.getElementById('container').innerHTML = browserify_hello_world.myfunc();
</script>
</html>
Node.js usage:
#!/usr/bin/env node
const browserify_hello_world = require('./index.js');
console.log(browserify_hello_world.myfunc());
Generate out.js for browser usage:
npx browserify --outfile out.js --standalone browserify_hello_world index.js
Both the browser and the command line show the expected output:
1 2 3
Tested with Browserify 16.5.0, Node.js v10.15.1, Chromium 78, Ubuntu 19.10.
To have your function available from both the HTML and from server-side node:
main.js:
var unique = require('uniq');
function myFunction() {
var data = [1, 2, 2, 4, 3];
return unique(data).toString();
}
console.log ( myFunction() );
// When browserified - we can't call myFunction() from the HTML, so we'll externalize myExtFunction()
// On the server-side "window" is undef. so we hide it.
if (typeof window !== 'undefined') {
window.myExtFunction = function() {
return myFunction();
}
}
main.html:
<html>
<head>
<script type='text/javascript' src="bundle.js"></script>
<head>
<body>
Result: <span id="demo"></span>
<script>document.getElementById("demo").innerHTML = myExtFunction();</script>
</body>
</html>
Run:
npm install uniq
browserify main.js > bundle.js
and you should get same results when opening main.html in a browser as when running
node main.js
Whole concept is about wrapping.
1.) Alternative - Object "this"
for this purpose I'll assume you have "only 1 script for whole app {{app_name}}" and "1 function {{function_name}}"
add function {{function_name}}
function {{function_name}}(param) { ... }
to object this
this.{{function_name}} = function(param) { ... }
then you have to name that object to be available - you will do it add param "standalone with name" like others advised
so if you use "watchify" with "browserify" use this
var b = browserify({
...
standalone: '{{app_name}}'
});
or command line
browserify index.js --standalone {{app_name}} > index-bundle.js
then you can call the function directly
{{app_name}}.{{function_name}}(param);
window.{{app_name}}.{{function_name}}(param);
2.) Alternative - Object "window"
add function {{function_name}}
function {{function_name}}(param) { ... }
to object window
window.{{function_name}} = function(param) { ... }
then you can call the function directly
{{function_name}}(param);
window.{{function_name}}(param);
You have a few options:
Let plugin browserify-bridge auto-export the modules to a generated entry module. This is helpful for SDK projects or situations where you don't have to manually keep up with what is exported.
Follow a pseudo-namespace pattern for roll-up exposure:
First, arrange your library like this, taking advantage of index look-ups on folders:
/src
--entry.js
--/helpers
--- index.js
--- someHelper.js
--/providers
--- index.js
--- someProvider.js
...
With this pattern, you define entry like this:
exports.Helpers = require('./helpers');
exports.Providers = require('./providers');
...
Notice the require automatically loads the index.js from each respective sub-folder
In your subfolders, you can just include a similar manifest of the available modules in that context:
exports.SomeHelper = require('./someHelper');
This pattern scales really well and allows for contextual (folder by folder) tracking of what to include in the rolled-up api.
You can also call your function from the html file like this:
main.js: (will be in bundle.js)
window.onload = function () {
document.getElementById('build-file')
.addEventListener('click', buildFile)
}
function buildFile() {
...
}
index.html:
<button id="build-file"">Build file</button>
window.LogData =function(data){
return unique(data);
};
Call the function simply by LogData(data)
This is just a slight modification to thejh's answer but important one
For debugging purposes I added this line to my code.js:
window.e = function(data) {eval(data);};
Then I could run anything even outside the bundle.
e("anything();");

RequireJS does not run data-main script before loading required modules

My project includes the following files:
./index.html
./js/main.js
./js/vendor/require.js
./js/viewmodel/vm.js
The index.html has the following relevant snippet:
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
</script>
The js/main.js file is as follows:
var root = this;
define('jquery', ['http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.3.js'], function () { return root.$; });
define('ko', ['http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.1.0.js'], function (ko) { return ko; });
The js/viewmodel/vm.js file...
define(['jquery', 'ko'],
function($, ko) {
return {
subject: 'world',
greeting: 'hello'
}
}
);
When you open a browser to index.html, then the browser tries to load a file called js/ko.js instead of using the module defined in main.js. It seems like the js file pointed to by the data-main attribute is not guaranteed to run before dependency resolution. This does not seem correct to me since one purpose of the data-main js file is to define require configuration (i.e. path, shim, etc). I am using require v2.1.2.
This works perfectly fine if I copy the contents of my main.js file into the script block in index.html. By "perfectly fine" I mean that it resolved ko to be a module and finds the appropriate CDN link to resolve ko instead of trying to download ./js/ko.js.
to use the data-main attribute for configuring your whole application, it is necessary that it is the single entry point for all your code.
your 2nd script block breaks this requirement by providing a 2nd entry point. since these entry points will resolve independently of each other (and asynchronously), you cannot rely on one to affect the other.
to resolve it, refactor your code in a way that provides a single entry point to your application and do your configuration via this entry point.
That's because requirejs sets the async. Attribute on the script.
The boolean async attribute on script elements allows the external
JavaScript file to run when it's available, without delaying page load
first.
This means that both scripts are loaded and evaluated parallel, so none of the two scripts can access methods or functions from the other one.
If you want to define requirejs variables in one script you mustn't load that script with require js.
For me there are three possibilities how you can solve that problem:
Add the content of main.js to your page (as you mention)
Load the main.js file without requirejs as normal script
Define the require config before loading the scripts (link to requirejs docu )
I had the same problem. The architecture of the site that i was working was components that was loading asynchronous at each part of the page.
Each component has its own html, css, and js code.
So, my solution is to keep a guard function for all the required dependency code, to protect them from running before the main javascript file:
index.html
<head>
<script type="text/javascript">
window.BeforeMainGuard = {
beforeMainLoadedFunctions: [],
hasMainLoaded: false,
guard: function( func ) {
console.assert( typeof func === 'function' );
if( this.hasMainLoaded ) {
func();
}else {
this.beforeMainLoadedFunctions.push( func );
}
},
onMainLoaded: function() {
for( var i = 0; i<this.beforeMainLoadedFunctions.length; ++i ) {
var beforeMainLoadedFunction = this.beforeMainLoadedFunctions[i];
beforeMainLoadedFunction();
}
this.beforeMainLoadedFunctions = null;
this.hasMainLoaded = true;
}
};
</script>
<script data-main="js/main.js" src="js/vendor/require.js"></script>
<script type="text/javascript">
window.BeforeMainGuard.guard( function() {
require(['viewmodel/vm', 'ko'],
function(viewmodel, ko) {
ko.applyBindings(viewmodel);
}
);
});
</script>
</head>
js/main.js
require.config({
// your config
});
require( [ 'AppLogic' ], function( AppLogic ){
AppLogic.Init();
window.BeforeMainGuard.onMainLoaded();
} );

Resources