Remix App Embed - javascript code bundling

Topic summary

The discussion addresses how to develop custom JavaScript code for Shopify app-embed extensions using TypeScript.

Core Challenge:

  • Extensions only accept .js files, not TypeScript
  • Need proper bundling/minification workflow that integrates with shopify app build and shopify app dev commands
  • Must ensure file watching and syncing during development

Recommended Solution:

  • Write code in TypeScript outside the extension directory
  • Use a bundler (Vite, Webpack, or esbuild) to transpile TypeScript to JavaScript
  • Configure build output to /extensions/.../assets directory
  • This allows shopify app dev to properly watch and sync changes

Implementation Example:
A working Webpack configuration was shared showing:

  • Extension code stored outside src/ directory
  • Output configured to extensions/<EXTENSION_NAME>/assets
  • TypeScript loader setup with proper file resolution
  • Entry point mapping to generate bundled .js files

The approach separates source TypeScript from compiled JavaScript, maintaining compatibility with Shopify’s extension requirements while preserving modern development workflows.

Summarized with AI on October 24. AI used: claude-sonnet-4-5-20250929.

What is the proper way to develop custom js code for app-embed?

Im looking for typescript and when i do shopify app build, bundle/minimify it in to app.js. But the question is how to store them?

Since extension can only contain .js files, and how to make it work properly with shopify app build/dev , so it will be bundled on build, and watched/synced on dev stage

Write your code in TypeScript, then transpile it to plain .js with a bundler (Vite, Webpack, or esbuild). Only the compiled .js goes in the extension folder, since Shopify doesn’t allow .ts files. Make sure your build script outputs to /extensions/.../assets so shopify app dev can watch and sync changes.

1 Like

VictoriaStudio is right. That’s what we do as well. Our extension code is in a directory outside of src/, and then we have set Webpack to build to extensions/ as its output. Here’s a simplified version of our config, might be helpful for you:

import path from "path";
import webpack from "webpack";

const __dirname = import.meta.dirname;

const outputDir = path.resolve(
  __dirname,
  "../extensions/<EXTENSION NAME HERE>/assets"
);

export const commonConfig: webpack.Configuration = {
  entry: {
    my_extension: "./my_extension.ts",
  },
  output: {
    path: outputDir,
    filename: "[name].js"
  },
  resolve: {
    extensions: [".ts", ".tsx", ".js"],
    extensionAlias: {
      ".js": [".js", ".ts"],
      ".cjs": [".cjs", ".cts"],
      ".mjs": [".mjs", ".mts"]
    }
  },
  module: {
    rules: [
      { test: /\.([cm]?ts|tsx)$/, loader: "ts-loader" }
    ]
  },
};

Best,

Tobe