How to add git hash to my project on build - Webpack - javascript

I would like to access some information about my project for testing purposes. For example, I'd like to append the git hash or and installed module version as a param on one of my requests. What I came up with (which works) is to include a prebuild script in my package.json
"prebuild": "node scripts/prebuild.js"
and in that script
var fs = require('fs');
var child_process = require('child_process');
const revision = child_process
.execSync('git rev-parse HEAD')
.toString().trim()
const module_version = child_process
.execSync('npm view module version')
.toString().trim()
const params = `module.exports = {
git_hash: '${revision}',
module_version: '${module_version}'
};`
fs.writeFileSync(__dirname + '/../src/helpers/params.js', params, () => {
console.log('Prebuild finished');
});
and then import that file where needed
import params from './src/helpers/params';
However this seems kinda hacky to me and I wonder if there's a way to utilize webpack to help me achieve this in a better/safer way.

Related

What is the best way to add APM to NuxtJS project

What is the right way to configure/enable an Elastic APM agent in a Nuxtjs project?
I referred this documentation for a custom NodeJS app. The key takeaway was:
It’s important that the agent is started before you require any other
modules in your Node.js application - i.e. before http and before your
router etc.
I added the following snippet in nuxt.config.js, but the APM agent is not started or working. I do not see any errors in the app logs.
var apm = require('elastic-apm-node').start({
serviceName: 'nuxt-app',
serverUrl: 'http://ELK_APM_SERVER:8200'
})
Is there any other way to do this?
We managed to get this working using a custom Nuxt module which explicitly requires the Node modules to instrument after it has initiated the APM module.
modules/elastic-apm.js:
const apm = require('elastic-apm-node');
const defu = require('defu');
module.exports = function() {
this.nuxt.hook('ready', async(nuxt) => {
const runtimeConfig = defu(nuxt.options.privateRuntimeConfig, nuxt.options.publicRuntimeConfig);
const config = (runtimeConfig.elastic && runtimeConfig.elastic.apm) || {};
if (!config.serverUrl) {
return;
}
if (!apm.isStarted()) {
await apm.start(config);
// Now explicitly require the modules we want APM to hook into, as otherwise
// they would not be instrumented.
//
// Docs: https://www.elastic.co/guide/en/apm/agent/nodejs/master/custom-stack.html
// Modules: https://github.com/elastic/apm-agent-nodejs/tree/master/lib/instrumentation/modules
require('http');
require('http2');
require('https');
}
});
}
nuxt.config.js:
module.exports = {
// Must be in modules, not buildModules
modules: ['~/modules/elastic-apm'],
publicRuntimeConfig: {
elastic: {
apm: {
serverUrl: process.env.ELASTIC_APM_SERVER_URL,
serviceName: 'my-nuxt-app',
usePathAsTransactionName: true // prevent "GET unknown route" transactions
}
}
}
};
All the answers are outdated and from beginning incorrect (17.02.2022)
To make it work follow these steps:
1.) Create a nodeApm.js in your root dir with the following content:
const nodeApm = require('elastic-apm-node')
if (!nodeApm.isStarted()) {
nodeApm.start()
}
2.) Use environment variables to store your config. For example:
ELASTIC_APM_SERVICE_NAME=NUXT_PRODUCTION
ELASTIC_APM_SECRET_TOKEN=yoursecrettokenhere
3.) Edit your package.json
"scripts": {
// if you want apm also on dev to test, add it also here
"dev": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt",
...
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
...
! Be awere that in ~2022 the node_modules bin folder has lost the "." in the directory name
! In all othere anwsers people forget the start parameter at the end
"start": "node -r ./nodeApm.js node_modules/nuxt/bin/nuxt start",
Based on what I've seen it looks like there isn't a "right" way to do this with the stock nuxt command line application. The problem seems to be that while nuxt.config.js is the first time a user has a chance to add some javascript, that the nuxt command line application bootstraps the Node's HTTP frameworks before this config file is required. This means the elastic agent (or any APM agent) doesn't have a chance to hook into the modules.
The current recommendations from the Nuxt team appears to be
Invoke nuxt manually via -r
{
"scripts": {
"start": "node -r elastic-apm-node node_modules/nuxt/.bin/nuxt"
}
}
Skip nuxt and use NuxtJS programmatically as a middleware in your framework of choice
const { loadNuxt } = require('nuxt')
const nuxtPromise = loadNuxt('start')
app.use((req, res) => { nuxtPromise.then(nuxt => nuxt.render(req, res)) })
Based on Alan Storm answer (from Nuxt team) I made it work but with a little modification:
I created a file named nodeApm.js where I added the following code:
const nodeApm = require('elastic-apm-node')
if (!nodeApm.isStarted()) { ... // configuration magic }
In script sections I added:
"start": "node -r ./nodeApm.js node_modules/nuxt/.bin/nuxt"

why fs.exists is not a function in react js ? what's wrong? [duplicate]

I have
import fs from 'fs'
and in my package.json I have
Then I run the command
> npm i fs
> fs#0.0.2 node_modules/fs
next in my React store I import 'fs' module
import fs from 'fs'
However when I try to use fs
I don't see methods except for constructor and a few other __methods. I don't see the method createReadStream or any other file manipulation methods.
Does anybody know what is wrong? (using Webpack) and can give more information upon request, but I am getting this far...
ps: why is it that I can npm i fs --save when I read on other posts that I do not have to do that (using node 5.5.0)
import Reflux from 'reflux'
import AddItemActions from '../actions/AddItemActions'
import request from 'superagent-bluebird-promise'
import fs from 'fs'
var ImageStore = Reflux.createStore({
init(){
.
.
.
},
decryptImage(file) {
var reader = new FileReader();
var info = {}
reader.onload = (output) => {
debugger
request.post("https://camfind.p.mashape.com/image_requests")
.set("X-Mashape-Key", "KEY")
.set("Content-Type", "application/x-www-form-urlencoded")
.set("Accept", "application/json")
.send({'focus': { 'x': 480}})
.send({'focus': { 'y': 640}})
.send({'image_request': {'altitude': 27.912109375}})
.send({'image_request': {'language': "en"}})
.send({'image_request': {'latitude': 35.8714220766008}})
.send({'image_request': {'locale' : "en_US"}})
.send({'image_request': {'longitude': 14.3583203002251}})
.send({'image_request': {'image': fs.createReadStream("/path" + 'file.jpg')}})
.then(function (result) {
console.log(result.status, result.headers, result.body);
this.info = result
},
function(error) {
console.log(error);
})
}
reader.readAsDataURL(file);
return info
},
.
.
.
.
})
In create-react-app they have stubbed out 'fs'. You cannot import it.
They did this because fs is a node core module.
You'll have to find another solution to that problem. See this ticket.
It's possible this might be an environment issue. It's not possible for the browser to interpret and run some Node server-side modules like fs.
The solution is to run the fs methods in a Node environment (server-side) or to find a package which offers the same functionality but written for the browser.
It's discussed in this question...
Module not found: Error: Cannot resolve module 'fs'
And this question...
Use fs module in React.js,node.js, webpack, babel,express
npm i babel-plugin-preval
Though browser does not allow accessing file system during runtime, You can use prevail in React to read content from file system into memory during build time
like so
// loading content of text file into react project during build time.
// which means everytime text content is changed, you need to rebuild the project to get the updated content.
const greetingContent = preval`
const fs = require('fs')
module.exports = fs.readFileSync(require.resolve('./greeting.txt'), 'utf8')
`
console.log(greetingContent);

SyntaxError: import declarations may only appear at top level of a module. Using express, no webpack

I am trying to import a npm module in the front end script. It is saying modules must be on top level to import but it is at the top level from what I can tell. Maybe my web server is messing with my code. I am unsure.
The code is ugly right now because I am trying to get everything situated.
I have already tried
<script type='module' src='./js/scripts.js'></script>
scripts.js
import axios from 'axios';
function getQueryStringValue (key) {
return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]" + encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&") + "(?:\\=([^&]*))?)?.*$", "i"), "$1"));
}
const query = getQueryStringValue('code');
class chime {
constructor(code) {
this.code = code;
};
async logIn() {
const response = await axios.post('url', {
'client_id': '',
'client_secret': '',
'grant_type': '',
'redirect_uri': 'https://localhost:3000',
'code': this.code
});
console.log(response);
}
test() {
console.log(this.code);
}
}
if (query) {
const client = new chime(query);
client.logIn();
};
var express = require('express')
var fs = require('fs')
var https = require('https')
var app = express()
const path = require('path');
const publicPath = path.join(__dirname, '../public');
const port = 3000;
app.use(express.static(publicPath));
app.get('*', (req, res) => {
res.sendFile(path.join(publicPath, '/index.html'));
});
https.createServer({
key: fs.readFileSync(path.join(__dirname + '/ssl/server.key')),
cert: fs.readFileSync(path.join(__dirname+ '/ssl/server.cert'))
}, app)
.listen(3000, function () {
console.log('Example app listening on port 3000! Go to https://localhost:3000/')
});
I am wanting to be able to import npm modules.
import axios from 'axios';
Bare module imports won't work in the browser. You need to use relative paths to a file that can be served by your web server (and not simply the NPM package name/a module exported by a package in node_modules and not a served directory), or a toolchain that can use a provided project root to generate the relative paths/pull in code from node_modules into a bundle.
It is saying modules must be on top level to import but it is at the top level from what I can tell
You didn't provide your entire setup, but using the implied hierarchy, I get Uncaught TypeError: Failed to resolve module specifier "axios". Relative references must start with either "/", "./", or "../". in Chrome, which is consistent with the above issue.
A quick and dirty way is to use the cdn:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
put it in your html file above your JavaScript tag
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script type='module' src="../app.js"></script>
</body>
Spent 2 hours and finally find a solution, the first thing you need to do is
npm i parcel-bundler -D
then package.json add the following two-line of codes
"scripts": {
"dev": "parcel index.html",
"build": "parcel build index.html"
}
finally
npm run dev.
and if you still have trouble, please open this link it just saves me so many hours.

Bundling with webpack from script

I am using webpack to bundle my Javascript files in my project:
webpack --config myconfig.webpack.config.
From commandline it is ok.
Building
However I would like to create a build task, I am using jake, so in order to create the bundle I need to invoke webpack from Javascript.
I could not find the API online, I basically need something like this:
// Jakefile.js
var webpack = require("webpack");
desc('This is the default build task which also bundles stuff.');
task('default', function (params) {
webpack.bundle("path-to-config"); // Something like this?
});
How do I achieve this?
Attempt 1
I have tried the following:
// Jakefile.js
var webpack = require("webpack");
var config = require("./webpack.config.js");
desc('This is the default build task which also bundles stuff.');
task('default', function (params) {
webpack(config);
});
webpack.config.js is my config for webpack. When I use from commandline and reference that file the bundle is correctly created. But when using the above code it does not work. When I execute it, no errors, but the bundle is not emitted.
In your Attempt 1, you seem to be consuming the webpack's Node.js API by passing the config to webpack method. If you take this approach, webpack method will return a compiler object and you need to handle it correctly.
For e.g.,
import webpack from 'webpack';
var config = {}; // Your webpack config
var wpInstanceCompiler = webpack(config);
wpInstanceCompiler.run(function(err, stats) {
if (stats.hasErrors()) {
console.log(stats.toJson("verbose");
}
});
This is how you execute a webpack config via the Node.js API. Unless you run the compiler instance, the output will not get generated.
This worked for me as well:
var webpack = require("webpack");
var lib = require(path.join(__dirname, "webpack.config.js"));
desc('Builds the projects and generates the library.');
task('default', function() {
webpack(lib, function() {
console.log("Bundle successfully created!");
});
});

Where do we put node modules we install by npm in a Meteor project?

I followed the github meteorirc project's lead and put them in /public/
I installed my node modules via npm from inside /public/ and therefore I have a /public/node_modules/ directory.
I don't think this is the 'proper' or 'standard' place for them because according to the Meteor docs...
Meteor gathers all your JavaScript files, excluding anything under the
client and public subdirectories, and loads them into a Node.js server
instance inside a fiber
The code to load is in the server dir and server js files and looks like this.
var require = __meteor_bootstrap__.require;
var path = require("path");
var fs = require('fs');
var base = path.resolve('.');
if (base == '/'){
base = path.dirname(global.require.main.filename);
}
var Twit;
var twitPath = 'node_modules/twit';
var publicTwitPath = path.resolve(base+'/public/'+twitPath);
var staticTwitPath = path.resolve(base+'/static/'+twitPath);
if (path.existsSync(publicTwitPath)){
Twit = require(publicTwitPath);
}
else if (path.existsSync(staticTwitPath)){
Twit = require(staticTwitPath);
}
else{
console.log('WARNING Twit not loaded. Node_modules not found');
}
Based on the docs this is not standard and I don't believe I should be doing it this way. Yet, it works both on my dev platform and in production at deploy meteor.com.
Where in the directory structure of the project should node modules be installed so that they work locally and upon deployment at meteor.com or elsewhere?
cd /usr/local/meteor/lib/ && npm install <module>
To use Npm modules in Meteor its adding the npm module in.
First you need to add a npm package adapter such as meteorhacks:npm
meteor add meteorhacks:npm
Then start your meteor app by running meteor, you will notice a new packages.json file in your project
Add in modules like this (you need to explicitly define a version)
{
"request" : "2.53.0"
}
Then you can use the npm modules in your meteor app, use Meteor.npmRequire instead of require
var request = Meteor.npmRequire("request")
Meteor takes lib/node_modules from the development bundle and makes a symbolic link or copies it to server/node_modules, which is in the hidden .meteor sub folder under your project.
So, if you cd into the lib directory of the development bundle or into server directory of the .meteor folder (I believe it is in build); you will be able to use the node modules. If you have trouble loading them, you might want to check out this question.
You have to add bundle folder to the path:
var staticTwitPath = path.resolve(base+'/bundle/static/'+twitPath);
Here is my working sample in coffeescript, node_modules are in public folder:
# loading node_modules from public folder
require = __meteor_bootstrap__.require
path = require("path")
fs = require('fs')
cheerioPath = 'node_modules/cheerio'
base = path.resolve('.')
if base == '/'
base = path.dirname(global.require.main.filename)
publicPath = path.resolve(base+'/public/'+cheerioPath)
staticPath = path.resolve(base+'/bundle/static/'+cheerioPath)
if path.existsSync(publicPath)
cheerio = require(publicPath)
else if path.existsSync(staticPath)
cheerio = require(staticPath)
else
console.log('node_modules not found')
Good luck!
This helped me a lot including a syntax highlighting package! Thanks!
I use a little helper though, as I think this will not be the last npm package I'll use ;)
meteorNpm = do() ->
require = __meteor_bootstrap__.require
path = require 'path'
fs = require 'fs'
base = path.resolve '.'
if base is '/'
base = path.dirname global.require.main.filename
meteorNpm =
# requires npm modules placed in `public/node_modules`
require: (moduleName) ->
modulePath = 'node_modules/' + moduleName
publicPath = path.resolve(base + '/public/' + modulePath)
staticPath = path.resolve(base + '/bundle/static/' + modulePath)
if path.existsSync(publicPath)
module = require publicPath
else if path.existsSync(staticPath)
module = require staticPath
else
module = null
return module
Use it like this:
highlight = meteorNpm.require "highlight.js"
I am using such script which nicely install all node.js dependencies. It behaves similar to official support in Meteor engine branch (it installs dependencies at runtime) but it supports also installing from git repositories and similar goodies.

Categories

Resources