Vue-CLI build number - does it exist and how could it be used in a Vue app itself? - vue.js

I have a Vue app being built for production deployment using Vue CLI.
I would like to include a typical incrementing build number in the application, so that I and testers can be sure we are testing the correct exact build. I would like to use it in the application in at least two ways a) to display it to a tester, and b) to included it in bug-tracking API calls e.g. to Sentry.io.
Currently I have to look at the hash on the app.XXXX.js and compare that. While this does uniquely identify the build, it's not sequential, is different for the CSS/JS/vendors etc and would be difficult to use in the codebase.
I'm happy to write a build wrapper script which manages the number and injects it into the build if that's what it takes.
The command I'm currently using is e.g.
npx vue-cli-service build --mode staging

I've implemented something using the date and time. It's in a Vue 2 project.
Add this code (or something like it) to the top of the vue.config.js file:
const verMajor = 1;
const verMinor = 0;
const now = new Date();
const padTwo = (val) => (val > 9 ? "" : "0") + val;
const nowMonth = now.getMonth() + 1;
const nowDay = now.getDate();
const verBuildDate = now.getFullYear() + padTwo(nowMonth) + padTwo(nowDay);
const verBuildTime = padTwo(now.getHours()) + padTwo(now.getMinutes()) + padTwo(now.getSeconds());
process.env.VUE_APP_VERSION = `${verMajor}.${verMinor}.${verBuildDate}.${verBuildTime}`;
console.log(`Building version: ${process.env.VUE_APP_VERSION}`);
// ...rest of the config
In the component code, you can do this:
get versionText(): string {
return process.env.VUE_APP_VERSION;
}
But I'm using class-based components so if you're not, I guess this will work instead:
computed: {
versionText: funnction () {
return process.env.VUE_APP_VERSION;
}
}
And in the template:
Ver: {{versionText}}
This results in something like:
Ver: 1.0.20211013.110634
If that looks too long, I'm sure it could be shortened according to your needs - or you could store a number in a file and write some JS in the config file to increment it on each build - or each release build if you check process.env.NODE_ENV === "release".
For further information, see: https://cli.vuejs.org/guide/mode-and-env.html
:o)

Related

How to remove window._nuxt_ in nuxt project, it is too large for me

When I use nuxt to develop my project, I find some problems.
window.__NUXT__=(function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_,$,aa, ..... code was too larger
can I remove it or use js file to replace it?
I have found a relatively perfect solution. I will share it with you here. You can also take a look at the website I developed using NUXT Sample Website
The key is the hook function vue-renderer:ssr:context, you can set the context.nuxt = null to remove any data in window._NUXT_.
But it is not work well, you have to add serverRender and routePath to window.nuxt
// nuxt.config.js
{
...,
hooks: {
'vue-renderer:ssr:context'(context) {
const routePath = JSON.stringify(context.nuxt.routePath);
context.nuxt = {serverRendered: true, routePath};
}
}
}
You can see the result at my site

Adding auto-ads with Vue.js

I have tried to add auto-ads to my website which uses Vue.js but there are no requests via the script.
I have tried the vue-adsense plugin, which can be found on npm https://www.npmjs.com/package/vue-google-adsense
but they have no support for auto-ads, normal ads work fine with this plugin.
This is the code which needs to be added:
<script data-ad-client="ca-pub-0990618353003742" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
Is there a solution for adding auto-ads on a vue.js site?
Script tags cannot be placed in a part of the DOM controlled by an instance of Vue(). All you need to do is place the script in the <head> of your document. If you are using Vue CLI to create your project, the file you do this in is /public/index.html.
You can init your ads how many you've added after change data. For example.
mounted: function () {
this.data = [1,2,3,4];
var adCount=3;
for (var i = 0; i < parseInt(adCount); i++) {
window.setTimeout(function () {
console.log('vue ad ' + i + ' inited');
(adsybygoogle = window.adsybygoogle || []).push({});
}, 300);
}
},

React Native, When converting a String to a Date, the result is different when in Debug mode

I want to convert the String to a date and compare it to the current one.
When I saw the results after coding Debug JS Remotely, it worked.
However, if Debug JS is stopped and then executed, the result will be changed to invalid Date.
How can I produce consistent results?
const checkNotice = async () => {
const noticeStart = new Date('2019-04-30 00:01:02');
const noticeEnd = new Date('2019-10-07 23:59:59');
const now = new Date();
if (now > noticeStart && now < noticeEnd) {
return {
NoticeStart: noticeStart,
NoticeEnd: noticeEnd,
};
}
return false;
};
When this code is in Debug mode
noticeStart and noticeEnd are replaced by Date.
However, if stop Debug mode, it will change to invalid Date and will always return false.
Everything else is the same.
Only the debug mode is different.
To compare two Date object, you can try doing
now.getTime() > noticeStart.getTime() && now.getTime() < noticeEnd.getTime()
Maybe this is because the behavior is different between the web browser JS interpreter and React Native JSCore. Have you looked at the issued on React-Native repository? ^^

React Native + Redux: Where to put functions for 3rd party libraries?

I'm creating an ecommerce app that uses a geolocation library (https://github.com/transistorsoft/react-native-background-geolocation).
I have an orderState:
const ordersInitState = {
lineItems: [],
status: ORDER_STATUSES.AWAITING_CHECKOUT,
};
const ordersReducer = (prevState=ordersInitState, action) => {
switch(action.type) {
...
case actions.ORDERS.REMOVE_ITEM:
const lineItems = [...prevState.lineItems];
const indexToRemove = action.payload;
lineItems.splice(indexToRemove, 1);
const status = lineItems.length > 0 ? prevState.status : ORDER_STATUSES.AWAITING_CHECKOUT;
return {
...prevState,
status,
lineItems,
};
default:
return prevState;
}
}
export default ordersReducer;
As you can see, the client is allowed to remove items from their cart. If they end up removing everything, their order status will reset. If they do end up emptying their cart (lineItems.length === 0) I want to also run a simple line from the geolocation library:
BackgroundGeolocation.removeGeofence("blah");
Where would I put this? It feels wrong to do it in the reducer because it has nothing to do with state. It also isn't specific to one particular component, so putting it in one of my components doesn't make sense.
I'm still a bit new to redux so I'm not sure where to put non-state related methods.
The often used name for what you are looking for is called "side effects" middleware. In the abstract, you want to cause an effect in an external system (in this case, the geolocation library), when the application state changes.
There are many libraries for this use case. Some of the more popular ones are redux-saga and redux-loop. They are both good tools and help give structure to managing complicated side effects, but both come with a significant conceptual overhead, and should only be used when really needed.
If you want a quick and simple solution, you can create a plain JavaScript module that subscribes to your store changes and executes the side effects for you:
import store from '../your/redux/store;
let previousCount = 0;
store.subscribe(() => {
const count = store.getState().orders.lineItems.length;
if (count === 0 && previousCount > 0) {
// someone just emptied the cart, so execute side-effect
BackgroundGeolocation.removeGeofence("blah");
}
previousCount = count;
});
And then if you find yourself needing this type of solution repeatedly, you can reach for one of the libraries mentioned above.

usemin revved filenames and requirejs dependencies

I'm running into the following problem with requirejs and usemin:
I want to setup a multipage application, where I dynamically load modules that only contain page specific functionality (e.g. about -> about.js, home -> home.js). I could go ahead and pack everything in a single file, but that just leads to a bigger file size and overhead on functionality that isn't necessary on each site! (e.g. why would I need to load a carousel plugin on a page that doesn't have a carousel!)
I checked out the example https://github.com/requirejs/example-multipage-shim
That is in fact a great way to deal with it, until I bring usemin into the game. After revving the filenames the src path of each script tag is updated, but what about the dependencies?
<script src="scripts/vendor/1cdhj2.require.js"></script>
<script type="text/javascript">
require(['scripts/common'], function (common) {
require(['app'], function(App) {
App.initialize();
});
});
</script>
In that case, require.js got replaced by the revved file 1cdhj2.require.js. Great!
But the required modules "common" and "app" no longer work since common became 4jsh3b.common.js and app became 23jda3.app.js!
What can I do about this? Thanks for your help!
(Also using Yeoman, btw)
It's a tricky problem and I'm sure somebody else fixed in in a more elegant way, but the following works for me.
I might publish this as a grunt plugin once it's a little more robust.
Taken from my Gruntfile:
"regex-replace": {
rjsmodules: { // we'll build on this configuration later, inside the 'userevd-rjsmodules' task
src: ['build/**/*.js'],
actions: []
}
},
grunt.registerTask('userevd-rjsmodules', 'Make sure RequireJS modules are loaded by their revved module name', function() {
// scheduled search n replace actions
var actions = grunt.config("regex-replace").rjsmodules.actions;
// action object
var o = {
search: '',
replace: '', //<%= grunt.filerev.summary["build/js/app/detailsController.js"] %>
flags: 'g'
};
// read the requirejs config and look for optimized modules
var modules = grunt.config("requirejs.compile.options.modules");
var baseDir = grunt.config("requirejs.compile.options.dir");
var i, mod;
for (i in modules) {
mod = modules[i].name;
revvedMod = grunt.filerev.summary[baseDir + "/" + mod + ".js"];
revvedMod = revvedMod.replace('.js', '').replace(baseDir+'/','');
o.name = mod;
o.search = "'"+mod+"'";
// use the moduleid, and the grunt.filerev.summary object to find the revved file on disk
o.replace = "'"+revvedMod+"'";
// update the require(["xxx/yyy"]) declarations by scheduling a search/replace action
actions.push(o);
}
grunt.config.set('regex-replace.rjsmodules.actions', actions);
grunt.log.writeln('%j', grunt.config("regex-replace.rjsmodules"));
grunt.task.run("regex-replace:rjsmodules");
}),
You can also use requirejs' map config to specify a mapping between your original module and your revved one.
Filerev outputs a summary object containing a mapping of all the modules that were versioned and their original names. Use grunt file write feature to write a file in AMD way with the contents being the summary object:
// Default task(s).
grunt.registerTask('default', ['uglify', 'filerev', 'writeSummary']);
grunt.registerTask('writeSummary', 'Writes the summary output of filerev task to a file', function() {
grunt.file.write('filerevSummary.js', 'define([], function(){ return ' + JSON.stringify(grunt.filerev.summary) + '; })');
})
and use this file in your require config so that the new revved modules are used instead of old ones:
require(['../filerevSummary'], function(fileRev) {
var filerevMap = {};
for (var key in fileRev) {
var moduleID = key.split('/').pop().replace('.js', '');
var revvedModule = '../' + fileRev[key].replace('.js', '');
filerevMap[moduleID] = revvedModule;
}
require.config({
map: {
'*': filerevMap
}
});
The filerevMap object that I created above is specific to my folder structure. You can tweak it as per yours. It just loops through the filerev summary and makes sure the keys are modified as per your module names and values as per your folder structure.