From Angular to Remix: Route by route migration
Tags: angular, remix, express, node
Published: 2023-01-30 20:44:25

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/](https://remix-angular.habibhinn.com/)

<iframe width="560" height="315" src="https://www.youtube.com/embed/umebAz5c-8w" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>


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](https://docs.npmjs.com/cli/v7/using-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.

![Project structure](https://res.cloudinary.com/habibhinn/image/upload/v1674814848/personal-blog/from-angular-to-remix-route-by-route-migration/Screen_Shot_2023-01-27_at_12.19.12_PM_kswgyl.png)

In order to change the Angular output build path, we need to update the `angular.json` file for both the `build` and `server` commands.


```json
"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": []
    },
```
```json
"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`:
```json
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "../build/out-tsc",
```

Also in Remix, we will update `remix.config.js`:
```javascript
/** @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:
```javascript
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: 
```javascript
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:
```javascript
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: 
```html
<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:
```html
<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](https://github.com/HinnHabib/angular-remix)
Original Article: [https://habibhinn.com/blog/from-angular-to-remix-route-by-route-migration](https://habibhinn.com/blog/from-angular-to-remix-route-by-route-migration)



## Learn more
[Remix](https://remix.run/)
[Angular](https://angular.io/)

If you liked this, click the ❤️ so other people will see it. Follow [me on Twitter](https://twitter.com/Hinn_Habib) and visit [my website](https://habibhinn.com) for more content!