nestjs / ng-universal

Angular Universal module for Nest framework (node.js) 🌷
https://nestjs.com
MIT License
442 stars 68 forks source link

Serve different build for desktop and mobile #79

Closed Bielik20 closed 3 years ago

Bielik20 commented 5 years ago

I'm submitting a...


[ ] Regression 
[ ] Bug report
[ ] Feature request
[x] Documentation issue or request
[ ] Support request => Please do not submit support request here, instead post your question on Stack Overflow.

Current behavior

No documentation on the subject

Expected behavior

Would love to see an example on how to serve different versions of an application depending on the device/size.

What is the motivation / use case for changing the behavior?

Imagine having an Angular app for the desktop web and an Ionic app for Android/iOS. It would be beneficial to serve the Ionic version on the web to those that enter it on their phones.

kamilmysliwiec commented 5 years ago

Honestly, I don't really understand what you would like to achieve. Could you elaborate, show some examples?

Bielik20 commented 5 years ago

@kamilmysliwiec Take Airbnb for example. If you enter it on desktop you will be served different application than on the mobile. It is not that site is responsive, it is different application.

vdjurdjevic commented 5 years ago

Youtube is another example. If you pick laptop in chrome responsive devtools, you get whole different application that accessing it with iphone for example. Now, both apps are made responsive, desktop version rearanges content based based od display width. The difference is that mobile app is native like design, it looks like native app, and its also responsive to look good on tables as well as small phones. I did that with my project and it works fine. I use ivy with angular and based on user agent i bootstrap different module dynamically. And on server, also based on user agent i just render different ng factory.

Bielik20 commented 5 years ago

@vladimirdjurdjevic Yes, that is exactly what I have in mind. Would you be able to share a code? It would be great if you could document this use case somehow.

vdjurdjevic commented 5 years ago

I will share it as soon as i get my hands on laptop. I could impement it here and submit a pull request this weekend if @kamilmysliwiec agrees

vdjurdjevic commented 5 years ago

Hey @Bielik20. Sorry for the delay. Here is what you can do:

if (device === DeviceType.Mobile) { return import('../app/mobile/mobile.module.browser').then(m => m.MobileModuleBrowser).then(m => platformBrowserDynamic().bootstrapModule(m)); } else { return import('../app/desktop/desktop.module.browser').then(m => m.DesktopModuleBrowser).then(m => platformBrowserDynamic().bootstrapModule(m)); }

`this._expressInstance.get('*', (req, res) => { req.originalUrl = req.path; req.baseUrl = req.path;

const device = new md(req.get('user-agent'));
let ngFactory = null;
let lazyModuleMap = null;

if (device.tablet() || device.mobile()) {
    ngFactory = mobileBundle.MobileModuleServerNgFactory;
    lazyModuleMap = mobileBundle.LAZY_MODULE_MAP;
} else {
    ngFactory = desktopBundle.DesktopModuleServerNgFactory;
    lazyModuleMap = desktopBundle.LAZY_MODULE_MAP;
}

res.set('Cache-Control', 'public, max-age=7200, s-maxage=14400');
res.render('index', {
    req,
    res,
    bootstrap: ngFactory,
    providers: [
        provideModuleMap(lazyModuleMap),
        {
            provide: REQUEST,
            useValue: req
        },
        {
            provide: RESPONSE,
            useValue: res
        }
    ]
});

});`

This will effectively render appropriate bundle on the server and provide initial view for the user, and also make sure that browser bootstraps appropriate bundle also with dynamic import. This could be also achieved with the router and lazy loading (also with dynamic import) so you don't have to build separate bundles for server-side. But you have to inject user agent from the server as an additional provider and reset routes based on device. Hope this gives you an idea what needs to be done, I can't share more than this since it's a private project.

Bielik20 commented 5 years ago

Ok, thank you, I needed this last part. Where exactly do you get that this._expressInstance from?

vdjurdjevic commented 5 years ago

I have class for my server, and that's just field. You can just call express()

Bielik20 commented 5 years ago

I would have to look more into it how to connect it with nestjs. Thank you.

kamilmysliwiec commented 3 years ago

We don't plan to add more features to this feature as it is supposed to be a tiny wrapper on top of @nguniversal/express-engine. If anyone needs more functionalities, we recommend forking this package and bringing it to the project's codebase.