Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OneSignal.push works but $nuxt.$OneSignal.push does not #3

Open
P4sca1 opened this issue Oct 25, 2019 · 27 comments
Open

OneSignal.push works but $nuxt.$OneSignal.push does not #3

P4sca1 opened this issue Oct 25, 2019 · 27 comments

Comments

@P4sca1
Copy link

P4sca1 commented Oct 25, 2019

Version

v3.0.0-beta.19

Reproduction link

https://staging.ips-hosting.com

Steps to reproduce

I am having a problem in my production deploy where the callback provided to $nuxt.OneSignal.push() is never called.
Everything works fine in dev.

Environment:

ubuntu: 18.04
node: 12.13
nuxt: 2.10.2
@nuxtjs/pwa: 3.0.0-beta.19
mode: universal

Here are the results of some tests I did in the browser console:

$nuxt.$OneSignal.push(() => { console.log("test") })
undefined
OneSignal.push(() => { console.log("test") })
VM125:1 test
undefined

As you can see $nuxt.$OneSignal.push is not working but OneSignal.push is.

I provided the url to my staging deployment where you can test yourself.

What is expected ?

The callback provided to $nuxt.$OneSignal.push should also be called in production.

What is actually happening?

OneSignal.push works but $nuxt.$OneSignal.push does not.

Additional comments?

If that helps, here is my Dockerfile:

# Base
FROM node:12.13-alpine as base

# Required build args, mapped to environment variables.
# Using a base image allows us to share those environment variables between the builder and the final image.
# This makes sense, because most environment variables are required both during build and during runtime.
ARG URL
ENV URL=$URL
ARG API_URL
ENV API_URL=$API_URL
ARG GA_TRACKING_ID
ENV GA_TRACKING_ID=$GA_TRACKING_ID
ARG STRIPE_API_KEY
ENV STRIPE_API_KEY=$STRIPE_API_KEY
ARG PAYPAL_CLIENT_ID
ENV PAYPAL_CLIENT_ID=$PAYPAL_CLIENT_ID
ARG ONESIGNAL_APP_ID
ENV ONESIGNAL_APP_ID=$ONESIGNAL_APP_ID

# Builder
FROM base as builder

WORKDIR /home/node/app

COPY .npmrc .
COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build && npm prune --production

# Final image
FROM base

RUN apk add --update --no-cache curl

USER node

RUN mkdir /home/node/app
WORKDIR /home/node/app

ENV NODE_ENV=production

EXPOSE 3000/tcp

COPY --from=builder --chown=node:node /home/node/app/.nuxt ./.nuxt
COPY --from=builder --chown=node:node /home/node/app/server-middleware ./server-middleware
COPY --from=builder --chown=node:node /home/node/app/static ./static
COPY --from=builder --chown=node:node /home/node/app/workbox ./workbox
COPY --from=builder --chown=node:node /home/node/app/nuxt.config.js .
COPY --from=builder --chown=node:node /home/node/app/package.json .
COPY --from=builder --chown=node:node /home/node/app/node_modules ./node_modules
COPY --from=builder --chown=node:node /home/node/app/healthcheck.sh ./healthcheck.sh

HEALTHCHECK \
  --interval=15s \
  --timeout=3s \
  --retries=3 \
  CMD /bin/sh /home/node/app/healthcheck.sh

CMD ["npm", "start"]

OneSignalSDK* is added to my .dockerignore.

This bug report is available on Nuxt community (#c178)
@matheuschimelli
Copy link

Are you calling $nuxt.$OneSignal.push from a page or component?

@P4sca1
Copy link
Author

P4sca1 commented Nov 10, 2019

@matheuschimelli From a component, vuex store and I also tried from the browser console.

@matheuschimelli
Copy link

matheuschimelli commented Nov 11, 2019

I'm using OneSignal on a project, so i tested on it. I tested using this this.$OneSignal.push(() => { console.log("TESTING ONESIGNAL USING THIS") }) and i tested using $nuxt $nuxt.$OneSignal.push(() => { console.log("TESTING ONESIGNAL $NUXT") }).
I ran both functions inside the created method and it worked. I also tested in production and it worked again.
Could you tell me where are you trying call $OneSignal ?

@P4sca1
Copy link
Author

P4sca1 commented Nov 11, 2019

Does it work through the browser console for you?

@matheuschimelli
Copy link

matheuschimelli commented Nov 11, 2019

Does it work through the browser console for you?

Yes it worked. It worked on the first try.
How is your nuxt.config.js? You have to put the OneSignal plugin before the pwa plugin

@P4sca1
Copy link
Author

P4sca1 commented Nov 12, 2019

The onesignal plugin is before the pwa plugin.
I will check whether building locally (not via docker) is working and get back to this issue afterwards.

@P4sca1
Copy link
Author

P4sca1 commented Nov 13, 2019

The problem seems to only occur when building via docker.

@matheuschimelli
Copy link

The problem seems to only occur when building via docker.

I'm not using Docker right now on my projects. I think i can try fix your Dockerfile later. If you fix the file, could you post it here? 😄

@P4sca1
Copy link
Author

P4sca1 commented Nov 14, 2019

Yes, I will try to figure out the reason for the problem and post it here.

@P4sca1
Copy link
Author

P4sca1 commented Nov 14, 2019

I think I found the issue.
The OneSignalSDKWorker.js and OneSignalSDKUpdateWorker.js are missing in the final build.
I added them to my .dockerignore, because I do not want to use the files that exist locally from previous builds. However because they are in the.dockerignore they are not copied over to the final image when running COPY --from=builder --chown=node:node /home/node/app/static ./static.

@P4sca1
Copy link
Author

P4sca1 commented Nov 14, 2019

Closing the issue as this is not an issue with the pwa module itself but with my build.

@P4sca1 P4sca1 closed this as completed Nov 14, 2019
@P4sca1
Copy link
Author

P4sca1 commented Nov 14, 2019

I got nuxt with pwa and onesignal working in production with docker using the following configuration.
The trick was to copy the pwa files generated during build explicitly to ignore that they are in .dockerignore.

Dockerfile

# Base
FROM node:12.13-alpine as base

# Required build args, mapped to environment variables.
# Using a base image allows us to share those environment variables between the builder and the final image.
# This makes sense, because most environment variables are required both during build and during runtime.
ARG URL
ENV URL=$URL
ARG API_URL
ENV API_URL=$API_URL
ARG GA_TRACKING_ID
ENV GA_TRACKING_ID=$GA_TRACKING_ID
ARG STRIPE_API_KEY
ENV STRIPE_API_KEY=$STRIPE_API_KEY
ARG PAYPAL_CLIENT_ID
ENV PAYPAL_CLIENT_ID=$PAYPAL_CLIENT_ID
ARG ONESIGNAL_APP_ID
ENV ONESIGNAL_APP_ID=$ONESIGNAL_APP_ID

# Builder
FROM base as builder

WORKDIR /home/node/app

COPY .npmrc .
COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build && npm prune --production

# Final image
FROM base

RUN apk add --update --no-cache curl

USER node

RUN mkdir /home/node/app
WORKDIR /home/node/app

ENV NODE_ENV=production

EXPOSE 3000/tcp

# Copy only the files needed from the builder to the final image.
# Note that some files like sw.js are in .dockerignore which is why we need to copy them explicitly.
COPY --from=builder --chown=node:node /home/node/app/.nuxt ./.nuxt
COPY --from=builder --chown=node:node /home/node/app/server-middleware ./server-middleware
COPY --from=builder --chown=node:node /home/node/app/static ./static
COPY --from=builder --chown=node:node /home/node/app/static/OneSignalSDK*Worker.js ./static/
COPY --from=builder --chown=node:node /home/node/app/static/sw.js ./static/sw.js
COPY --from=builder --chown=node:node /home/node/app/workbox ./workbox
COPY --from=builder --chown=node:node /home/node/app/nuxt.config.js .
COPY --from=builder --chown=node:node /home/node/app/package.json .
COPY --from=builder --chown=node:node /home/node/app/node_modules ./node_modules
COPY --from=builder --chown=node:node /home/node/app/healthcheck.sh ./healthcheck.sh

HEALTHCHECK \
  --interval=15s \
  --timeout=3s \
  --retries=3 \
  CMD /bin/sh /home/node/app/healthcheck.sh

CMD ["npm", "start"]

.dockerignore

*
!assets
!components
!graphql
!layouts
!middleware
!modules
!pages
!plugins
!server-middleware
!static
static/OneSignalSDK*Worker.js
static/sw.js
!store
!types
!workbox
!.npmrc
!healthcheck.sh
!nuxt.config.js
!package*.json
!tsconfig.json
.DS_Store

@P4sca1
Copy link
Author

P4sca1 commented Jan 9, 2020

For some reason this started to not work anymore again. I digged into this a little deeper and found out that window.OneSignal (which is working) is different from window.$OneSignal and $nuxt.$OneSignal (both are not working):

> window.OneSignal
< class vt{static setDefaultNotificationUrl(e){return a.a(this,void 0,void 0,function*(){if(!ft.isValidUrl(e,{allowNull:!0}))throw new InvalidArgumentError.a("url",InvalidArgumentError.b.Malformed);yield Obj…
> window.$OneSignal
< OneSignalStubES6 {VERSION: 150712, log: {…}, directFunctionCallsArray: Array(1), preExistingArray: undefined, on: ƒ, …}
> $nuxt.$OneSignal
< OneSignalStubES6 {VERSION: 150712, log: {…}, directFunctionCallsArray: Array(1), preExistingArray: undefined, on: ƒ, …}

OneSignal creates the OneSignalStubES6 early and replaces it with the full OneSignal class after it completely loaded.

Here's my guess on why the problem occurs:
window.OneSignal is replaced with the correct class (see here), but window.$OneSignal, $nuxt.$OneSignal remain of type OneSignalStubES6. So when using this.$OneSignal.push inside a component you are pushing to the stub, which works before OneSignal has loaded, but not after it completely loaded.

That being said, I have no clue on why this used to work after updating my Dockerfile or why this works in dev.

@P4sca1 P4sca1 reopened this Jan 9, 2020
@buglavecz
Copy link

Hi @P4sca1,

My issue is same like yours: https://github.com/nuxt-community/pwa-module/issues/263

I don't understand what is the reason, that is not working in a production environment...

Any idea?

Thanks.

@P4sca1
Copy link
Author

P4sca1 commented Jan 14, 2020

If I understand correctly, your issue is different from mine, because at least $OneSignal.push works for you all the time.
Those issues might still be related, because something is definitely not working correctly.

@P4sca1
Copy link
Author

P4sca1 commented Jan 16, 2020

My recent build is working for whatever reason. Feels very random.
Update: Working in Brave but not in Chrome.

@buglavecz
Copy link

buglavecz commented Jan 16, 2020

In PROD enviroment:
If I unregister Service Worker in devtools and after refresh Chrome, it is working. Again and again...
But, I no unregister service worker manually, just I refresh Chrome, again and again, then very randomly works.

In DEV environment all working fine.

@P4sca1
Copy link
Author

P4sca1 commented Jan 16, 2020

I also noticed unregistering the service worker sometimes fixes the issue and sometimes breaks it again.

@buglavecz
Copy link

buglavecz commented Jan 17, 2020

Hi @P4sca1 ,

I'm downgrade beta version to 2.6.0, and i tested and this it's works both environment: dev/prod.

@buglavecz
Copy link

Important: I use the window.OneSignal object, with window.$OneSignal or this.$OneSignal it's don't working...

@P4sca1
Copy link
Author

P4sca1 commented Jan 18, 2020

Interesting, thank you for the info.
I just tried using window.OneSignal everywhere instead of this.$OneSignal for v3, but this does not work. Downgrading to v2 is not an option for me.
@pi0 do you have an idea on why OneSignal seems to no longer work in v3?

@buglavecz
Copy link

I'm downgrade @nuxt/pwa also 2.6.0, not just onesignal module.
The v3 is currently beta, maybe this is the reason why don't works correctly. :-)

@pi0 please support us. :-)

Thank you.

@ghost
Copy link

ghost commented Apr 1, 2020

URGENT
I've the same issue when in production build. Everything works fine on my dev mode. Please note that I am using this inside a component and the mode of my nuxt application is SSR also am not using any docker services. Please let me know, it'll be a great help.
`

Subscribe to Notifications
Un-Subscribe from Notifications <style scoped> #my-notification-button{ position: fixed; bottom: 0; left: 0; padding: 10px; width: 100%; text-align: center; background-color: white; text-decoration: none; color: black; cursor: pointer; } </style> <script> export default { data(){ return { supportedBrowser: false, isSubscribed: false, currentDevice: null } }, mounted(){ this.isSubscribed = this.$auth.loggedIn ? this.$auth.user.notify : false; var OneSignal = window.$OneSignal; OneSignal.push(() => { OneSignal.on('subscriptionChange', this.update); }); this.update(); }, methods: { update(){ this.$OneSignal.push(async () => { var isPushSupported = await this.$OneSignal.isPushNotificationsSupported(); this.supportedBrowser= isPushSupported; if (isPushSupported) { var isEnabled = await this.$OneSignal.isPushNotificationsEnabled(); var deviceId = await this.$OneSignal.getUserId(); this.isSubscribed = isEnabled; this.currentDevice = deviceId; var reqBody = { isSubscribed: this.isSubscribed, currentDevice: this.currentDevice } if (isEnabled) { var response = await this.$axios.post("/users/subscribe", reqBody); } else { console.log("Notifications are not enabled"); var response = await this.$axios.post("/users/unsubscribe", reqBody); } } else { console.log("Does not support notifications"); } }); }, subscribe(){ console.log("here"); this.$OneSignal.push(async () => { console.log("here1"); var isSubscribed = await this.$OneSignal.setSubscription(true); }); }, unsubscribe(){ console.log("here2"); this.$OneSignal.push(async () => { console.log("here3"); var isSubscribed = await this.$OneSignal.setSubscription(false); }); } } } </script>`

@P4sca1
Copy link
Author

P4sca1 commented Apr 1, 2020

@lovishagg
I am also using it inside a component with SSR, maybe that is an issue? Would be great to hear if anybody got this working in production and how they configured OneSignal.

@ghost
Copy link

ghost commented Apr 1, 2020

@P4sca1 Please let me know if there's an alternative for push notifications which is reliable enough as the project is related to health care and I can not afford to mess up the things in notifications segment of the webapp/PWA

@P4sca1
Copy link
Author

P4sca1 commented Apr 1, 2020

I know that there are some commercial products available, but I don't have experience with implementing them. Would be great to get this issue sorted out, so that we can use OneSignal reliably with Nuxt.js @pi0

@pi0 pi0 transferred this issue from nuxt-community/pwa-module Apr 16, 2020
@cdrandin
Copy link

cdrandin commented May 8, 2020

I have been looking into this and noticed a couple of things.

@P4sca1 Is correct in his observations above. It is what I noticed as well.

The behaviour I am consistently noticing OneSignal doesn't exist if the script OneSignalPageSDKES6.js?v= isn't loaded "quickly" enough. I am unsure if it is quick enough or some chain of events I am not seeing yet. Which is being called on the start event in https://cdn.onesignal.com/sdks/OneSignalSDK.js:formatted:428.

This is based on a few breakpoints and examining the network tab. It all breaks and OneSignal doesn't become an OneSignalStub, but rather [] if OneSignalPageSDKES6.js isn't called "quickly" enough.

So, this is the async issue that OneSignal makes aware of. There isn't really a hook for us to use to let us know when the OneSignalStub is ready.

In any event, despite this being the issue OneSignal that got imported works just fine, but anything in $OneSignal sometimes works.

From playing around a lot I believe the issue to be the inject method. From the VueForums Injected properties are not reactive by design. Despite this being from 2017 I did some testing and it is still the case. I Injected an empty array and later trying to change it to an empty object and it was still an array.

Now in terms of a decent solution to this. I suppose there could be a few ways.

  • Pass OneSignal differently, so it can be reactive, to each component (minor change, not sure how to do this yet)
  • Change how we access OneSignal (major change, simple fix)

I am currently going through the nuxt modules docs to try to figure out how to do the former, but in the meantime, the latter would be the following:

// change
inject('OneSignal', OneSignal)

// to
inject('OneSignal', () => OneSignal)

all forms of this.$OneSignal would have to be accessed like this.$OneSignal() in the component.

This so far has been working for me. If anyone else could try this for there setup to see how resilient it is.

If there is any reason not to do it. cool. Just let me know. This is definitely a more workaround solution until further discussion can go into resolving this. @pi0

Edit:
I found that Vue.observable kind of works, but requires a bit more extra steps and changes how you access OneSignal more than the above method.

When you do Vue.observable({OneSignal} it will lose reference since OneSignal changes entirely when it loads and isn't the same in Vue.observable. Sure we can use Vue.set, but a place where you can be sure it works is on the OneSignal push method for it to be called when the object does load.

I guess meantime just use window.OneSignal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants