In this tutorial, we will show you how to migrate an Angular application to Remix by running Angular Universal and Remix projects side by side on the same Express.js server. We will provide an example, source code, and screenshots to help you understand the process.
An example of the final application that contains Angular Universal and Remix running side by side on the same ExpressJS server can be found at: https://remix-angular.habibhinn.com/
When we run build commands for either framework, it will generate the server-side scripts and the client-side scripts. These scripts handle the rendering of the application on the server and the transfer of the rendered HTML to the client.
To start, we will use npm workspaces to manage multiple projects in the same repo. Create two subfolders - one for the Angular source code and one for the Remix source code. Also, we will create a build folder that contains the output bundle for both projects.
In order to change the Angular output build path, we need to update the angular.json
file for both the build
and server
commands.
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "../build/browser/angular",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "tsconfig.app.json",
"assets": ["src/favicon.ico", "src/assets"],
"styles": ["src/styles.css"],
"scripts": []
},
"server": {
"builder": "@angular-devkit/build-angular:server",
"options": {
"outputPath": "../build/server/angular",
"main": "server.ts",
"tsConfig": "tsconfig.server.json"
},
Also update outDir in tsconfig.ts
:
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "../build/out-tsc",
Also in Remix, we will update remix.config.js
:
/** @type {import('@remix-run/dev').AppConfig} */
module.exports = {
ignoredRouteFiles: ["**/.*"],
appDirectory: "app",
assetsBuildDirectory: "../build/browser/remix",
serverBuildPath: "../build/server/remix/index.js",
publicPath: "/browser/",
};
Now, you will need to configure Express.js server to handle both client side javascript and server side scripts for both frameworks. In this tutorial we will update angular server to serve remix routes. (It can be done the other way)
Add to server.ts to handle client side scripts:
server.use(
// Note: must match remix.config.js publicPath value
'/browser',
// Note: must match remix.config.js assetsBuildDirectory value
express.static('../build/browser/remix'), {
immutable: true,
maxAge: '1y',
})
);
Also add server side scripts:
server.get(
// Path or URL that should resolve to remix
'/remix*',
// Note: must match remix.config.js assetsBuildDirectory value
createRequestHandler({
// remix.config.js serverBuildPath
build: require('../build/server/remix'),
})
);
so the full code for the server.ts file should be:
export function app(): express.Express {
const server = express();
const distFolder = join(BROWSER_FILES_BASE_PATH, 'angular');
const indexHtml = existsSync(join(distFolder, 'index.original.html'))
? 'index.original.html'
: 'index';
// Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
server.engine(
'html',
ngExpressEngine({
bootstrap: AppServerModule,
})
);
server.set('view engine', 'html');
server.set('views', distFolder);
server.use(
'/browser',
express.static(join(BROWSER_FILES_BASE_PATH, 'remix'), {
immutable: true,
maxAge: '1y',
})
);
server.get(
'/remix*',
createRequestHandler({
build: require('../build/server/remix'),
})
);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get(
'*.*',
express.static(distFolder, {
maxAge: '1y',
})
);
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, {
req,
providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }],
});
});
return server;
}
Not to switch easily between two frameworks for the users while navigating between application we will use anchor tag as it will do a full page refresh.
Remix:
<header className="bg-indigo-600">
<nav className="mx-auto max-w-7xl px-6 lg:px-8" aria-label="Top">
<div className="flex w-full items-center justify-between border-b border-indigo-500 py-6 lg:border-none">
<div className="flex items-center">
<div className="ml-10 block space-x-8">
<!-- Defined as anchor tag to do full page refresh -->
<a
href={"/"}
className="text-base font-medium text-white hover:text-indigo-50"
>
Angular Application
</a>
<Link
to="/remix"
className="text-base font-medium text-white hover:text-indigo-50"
>
Remix Application
</Link>
</div>
</div>
</div>
</nav>
</header>
Angular:
<header class="bg-indigo-600">
<nav class="mx-auto max-w-7xl px-6 lg:px-8" aria-label="Top">
<div
class="flex w-full items-center justify-between border-b border-indigo-500 py-6 lg:border-none"
>
<div class="flex items-center">
<div class="ml-10 block space-x-8">
<a
routerLink="/"
class="text-base font-medium text-white hover:text-indigo-50"
>
Angular Application
</a>
<!-- Defined as anchor tag to do full page refresh -->
<a
href="/remix"
class="text-base font-medium text-white hover:text-indigo-50"
>
Remix Application
</a>
</div>
</div>
</div>
</nav>
</header>
Source code: GitHub
Original Article: https://habibhinn.com/blog/from-angular-to-remix-route-by-route-migration
Learn more
If you liked this, click the ❤️ so other people will see it. Follow me on Twitter and visit my website for more content!
Top comments (0)