Docly Developers
Knowledge base Best practice Recommended

Carry a separate mobile site over as its own module

In shortWhen the site you convert has a separate mobile version (m.example.com) that shows the same pages, keep it as its own module: one data folder with the content, published twice — a desktop app on www and a mobile app on m. A router in the desktop app sends phones to the same path on m, with the mobile address per host in #/Config. The content is edited once; what only the mobile site has (logo, intro, quick menu, which list layout a folder uses) is fields.
Applies to ConversionAppsPublishingRouter
  1. What you'll see

    The site you are converting answers phones from m.example.com: www.example.com/menu with an iPhone redirects to m.example.com/menu, which shows the same text with its own header, menu, footer and list layouts. The old CMS did this with a second design on the same content. Building one responsive site instead changes the solution the customer has, and the mobile pages can no longer be measured against the original.

  2. What's actually happening

    Check what the mobile site is before you build it. On a converted eSite site (sant.no) every one of the 38 content pages existed on both hosts with the same path and the same text; what differed was the frame (header, menu, quick menu, footer), the front page, a short intro on the section front pages, and the markup of the folder listings. Measure which devices are redirected with curl -A: there iPhone, iPod, Windows Phone and Android phones were sent to m, but iPad, Android tablets and desktops were not. A crawler that only follows href may find just the front page of an old mobile site, whose menu used onclick — start it with the desktop paths.

    The shape is the multi-module layout (see Build a multi-module solution on one data folder): one folder for the solution holding the data folder and two Docly App folders. The data folder holds the pages, #/Schemas, #/Config, #/site.json and what both apps share. It is published twice, each publication naming its app as template.

    • Display templates belong in the apps. A #/<Schema>.hash in the data folder's # wins over the app's and renders the desktop markup on the mobile site too.
    • Shared code belongs in the data folder: #/Libs/… (for example the function that builds a listing from the fields), #/Partials/… (a form both sites show), #/Root/… (a stylesheet both use). A #/ path resolves in the data folder first, then in the publication's app, and import works in .hash templates.
    • What only the mobile site has is content: the mobile logo, menu button image, top image, intro and quick menu are fields on the section's own page; which mobile layout a folder listing used is a dropdown field.
    • The redirect is a router in the desktop app (route.redirect, 302 — the answer depends on the device, and a 301 can be remembered for the address). The mobile address comes from #/Config, one row per host, so the test address can be tried and go-live changes no code; a host without a row sends nobody. The mobile app's router only handles old addresses.

    In the router, request.url is the path below the site, docly.getHeader("User-Agent") and docly.getHeader("Host") give the device and host, and the query string is the host dictionary query. Measured on c5: Object.keys(query) throws and for…in walks the dictionary's own members (Count, Keys …); JSON.parse(JSON.stringify(query)) gives the keys and values.

  3. What to do

    Do:

    1. Map the mobile site: pages, text, layouts per page type, what is mobile-only, and the user agents that are redirected.
    2. Create the solution folder with the data folder and two Docly App folders. docly mkdir --schema does not set the type today — write each app folder's .docly with "Schema": "Docly App" and push.
    3. Move the desktop templates into the desktop app; put shared code in the data folder's #/Libs, #/Partials and #/Root.
    4. Publish the data folder twice with docly publish <data folder> --domain … --alias … --template <app>.
    5. Add the router to the desktop app's site.json:
      // Services/Router.js
      import { tilMobil } from "#/Libs/Ruting.js";
      export default (route) => tilMobil(route) || route.next();
      where tilMobil checks the User-Agent with the same rule as the old site, finds the row for getHeader("Host") in #/Config, and returns route.redirect(address + request.url + query string, 302).
    6. Measure the mobile site against the original with a phone user agent, isMobile, at 360 and 390 px, so the page's viewport meta applies as on a phone.

    Don't:

    • a second copy of the content for the mobile site,
    • display templates in the data folder's #,
    • a mobile address written into code,
    • a responsive rewrite when the task is to carry the existing solution over — offer it to the customer as a later improvement.

Last reviewed 03 Nov 2026