Webpack: access to function defined in index.js from an HTML page

Viewed 26

I am trying to bundle a typescript project and use such bundle in a browser. I think I was able to generate correctly the bundle but I don't know how to access to the project code from a HTML page.

Below a simplified version of my project:


    myproj/src/MyEntryPointClass.ts
    myproj/src/OtherClass.ts
    myproj/src/YetAnotherClass.ts
    myproj/src/index.js
    
    myproj/package.json
    myproj/webpack.config.cjs
    myproj/tsconfig.json

src/MyEntryPointClass.ts


    import { OtherClass } from "./OtherClass";
    import { YetAnotherClass } from "./YetAnotherClass";
    export class MyEntryPointClass {
    
        _myparam: string;
    
        constructor(param: string){
            this._myparam = param;
    
        }
    
        async method1(): Promise<OtherClass> {
            return "Method 1 says: "+this._myparam;
        }
    }

src/index.js


    import {MyEntryPointClass} from './MyEntryPointClass.ts'
    
    
    function myAPI(myparam){
        const mep = new MyEntryPointClass(myparam);
        return mep.method1();
    }

package.json


    {
      "type": "module",
      "name": "my-webpack-project",
      "version": "1.0.0",
      "description": "My webpack project",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack --mode=production --node-env=production",
        "build:dev": "webpack --mode=development",
        "build:prod": "webpack --mode=production --node-env=production",
        "watch": "webpack --watch"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@types/jest": "^29.0.0",
        "@types/node-fetch": "^2.6.2",
        "@types/webpack": "^5.28.0",
        "@typescript-eslint/eslint-plugin": "^5.36.1",
        "@typescript-eslint/parser": "^5.36.1",
        "@webpack-cli/generators": "^2.5.0",
        "clean-webpack-plugin": "^4.0.0",
        "css-loader": "^6.7.1",
        "domhandler": "^5.0.3",
        "eslint": "^8.23.0",
        "eslint-config-prettier": "^8.5.0",
        "eslint-plugin-prettier": "^4.2.1",
        "fs": "^0.0.1-security",
        "html-webpack-plugin": "^5.5.0",
        "jest": "^28.1.3",
        "mini-css-extract-plugin": "^2.6.1",
        "path": "^0.12.7",
        "prettier": "^2.7.1",
        "source-map-js": "^1.0.2",
        "style-loader": "^3.3.1",
        "ts-jest": "^28.0.8",
        "ts-loader": "^9.3.1",
        "typescript": "^4.8.3",
        "webpack": "^5.74.0",
        "webpack-cli": "^4.10.0",
        "webpack-node-externals": "^3.0.0",
        "wepack-cli": "^0.0.1-security"
      },
      "dependencies": {
        "buffer": "^6.0.3",
        "node-fetch": "^2.6.7",
        "process": "^0.11.10"
      }
    }

webpack.config.cjs


    // Generated using webpack-cli https://github.com/webpack/webpack-cli
    
    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    const MiniCssExtractPlugin = require("mini-css-extract-plugin");
    const webpack = require('webpack')
    
    const isProduction = process.env.NODE_ENV == "production";
    
    const stylesHandler = MiniCssExtractPlugin.loader;
    
    const config = {
      entry: "./src/index.js",
      output: {
        path: path.resolve(__dirname, "dist"),
        chunkFilename: '[name].js',
        filename: '[name].js'
      },
      plugins: [
        // fix "process is not defined" error:
        // (do "npm install process" before running the build)
        new webpack.ProvidePlugin({
          process: 'process/browser',
        }),
    
        new MiniCssExtractPlugin(),
    
        // Add your plugins here
        // Learn more about plugins from https://webpack.js.org/configuration/plugins/
      ],
      module: {
        rules: [
          {
            test: /\.(ts|tsx)$/i,
            loader: "ts-loader",
            exclude: ["/node_modules/"],
          },
          {
            test: /\.css$/i,
            use: [stylesHandler, "css-loader"],
          },
          {
            test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
            type: "asset",
          },
    
          // Add your rules for custom modules here
          // Learn more about loaders from https://webpack.js.org/loaders/
        ],
      },
      resolve: {
        extensions: [".tsx", ".ts", ".jsx", ".js", "..."],
        fallback: {
          "fs": false,
          "tls": false,
          "net": false,
          "path": false,
          "zlib": false,
          "http": false,
          "https": false,
          "stream": false,
          "crypto": false,
          "url": false,
          "util": false,
          "buffer": false
        },
      },
      devtool:'source-map',
    };
    
    module.exports = () => {
      if (isProduction) {
        config.mode = "production";
      } else {
        config.mode = "development";
      }
      return config;
    };

And after running $ npm run build, the bundle gets generated in dist dir:


    $ ll dist
    drwxr-xr-x   5 fgiordano  1276952531     160 Sep 11 17:01 .
    drwxr-xr-x  14 fgiordano  1276952531     448 Sep 11 17:18 ..
    -rw-r--r--   1 fgiordano  1276952531   26945 Sep 11 17:08 main.js
    -rw-r--r--   1 fgiordano  1276952531  123651 Sep 11 17:11 main.js.map

Though, I created a dist/idex.html where I'd like to call my project by passing a variable.


    <!doctype html>
    <html>
    
    <head>
        <meta charset="utf-8" />
        <title>Webpack App</title>
        <base href="."/>
        <script defer="defer" type="module" src="./main.js"></script>
    </head>
    
    <body>
        <h1>Testing generated bundle</h1>
        <script>
            let paramTest = "Hello! Yes, it works";
            let message = myAPI(paramTest);
            console.log(message);
        </script>
    </body>
    
    </html>

Abd here comes the error. By looking at the Developer Tools console in the browser I get: Uncaught ReferenceError: myAPI is not defined http://127.0.0.1:5501/dist/index.html

Could you please help me in understanding where am I mistaking? I am a bit lost. Thanks all.

1 Answers

As you are using defer in your script -

<script defer="defer" type="module" src="./main.js"></script>

This will cause main.js to load it in asynchronous mode and below script will execute before main.js loads, that will lead to Uncaught ReferenceError: myAPI

<script>
    let paramTest = "Hello! Yes, it works";
    let message = myAPI(paramTest);
     console.log(message);
</script>

Few solutions -

  1. Remove defer
  2. Add this code in some file which will get bundled into main.js
Related