A question about the combination of Typescript and React in plugins

I don’t have much experience using React in plugins, let alone the combination of React and Typescript. However, the complexity of a new project leaves me wanting to use this combination.

However, I’m currently facing a problem when trying to run the built plugin (and hope somebody has experience with this and can shed some light):

In my webpack.config.js, I load the .tsx files using the ts-loader:

// webpack.config.js

module.exports = {
    entry: './src/main.tsx',
    output: {
        path: __dirname,
        filename: 'dist/main.js',
        libraryTarget: 'commonjs2'
    },
    externals: {
        assets: 'assets',
        scenegraph: 'scenegraph',
        application: 'application',
        commands: 'commands',
        clipboard: 'clipboard',
        cloud: 'cloud',
        uxp: 'uxp',
        viewport: 'viewport',
        interactions: 'interactions'
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                use: 'ts-loader',
                exclude: /node_modules/,
            },
        ],
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js', '.jsx'],
    },
};

Now: As soon as I import an external dependency (in this case: React from react, as I have to, with React), the code gets transpiled to using eval statements in the output for all dependent libraries.

Of course, XD doesn’t support the eval function and therefore prints the following output:

Plugin EvalError: Code generation from strings disallowed for this context
    at Object../src/main.tsx (<settings>\develop\de.pabloklaschka.xdplugins.chat\main.js:242:1)
    at __webpack_require__ (<settings>\develop\de.pabloklaschka.xdplugins.chat\main.js:21:30)
    at <settings>\develop\de.pabloklaschka.xdplugins.chat\main.js:85:18
    at <settings>\develop\de.pabloklaschka.xdplugins.chat\main.js:88:10
    at e.exports._loadModule (uxp://uxp-internal/runtime_scripts_loader.js:1:16825)
    at e.exports.loadMainModule (uxp://uxp-internal/runtime_scripts_loader.js:1:14482)
    at Object.loadMainFile (uxp://uxp-internal/pluginmanager_scripts.js:1:20242)
    at N.loadMainFile (uxp://uxp-internal/pluginmanager_scripts.js:1:7553)
    at loadPlugin (plugins/PluginLoader.js:1:648)
    at plugins/PluginLoader.js:1:9175
    at convertPluginErrorToString (plugins/PluginErrorUtil.js:1:198)
    at safeGetStackTrace (plugins/PluginErrorUtil.js:1:339)
    at internalFormatPluginError (plugins/PluginErrorUtil.js:1:1073)
    at internalReportPluginError (plugins/PluginErrorUtil.js:1:1171)
    at Object.reportPluginError (plugins/PluginErrorUtil.js:1:1603)
    at loadPlugin (plugins/PluginLoader.js:1:1416)
    at plugins/PluginLoader.js:1:9175
    at Array.forEach (<anonymous>)
    at reloadPlugins (plugins/PluginLoader.js:1:9149)
    at Artwork.history.waitForCurrentEditBatch.then (plugins/PluginLoader.js:1:9824)

Does anyone know a way to stop ts-loader (or, of course, Typescript) from producing eval-“infected” output?

Thank you so much in advance.


Other files:

// tsconfig.json
{
  "compilerOptions": {
    "outDir": "./dist/",
    "strict": true,
    "target": "es2015",
    "module": "commonjs",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "allowJs": true,
    "checkJs": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "jsx": "react"
  },
  "include": [
    "src/**/*"
  ]
}
// main.ts

import { RootNode } from 'scenegraph';
import DocumentModel from './model/document-model';
import { render } from 'react-dom';
import Chat from './components/chat';
import React = require('react');

async function myCommand(selection: XDSelection, root: RootNode) {
    root.pluginData = new DocumentModel();

    const elem = document.createElement('dialog');
    render(<Chat model={root.pluginData} />, elem)
    console.log('My Plugin');
}

export default {
    commands: {
        myCommand
    }
};
// The React component

import DocumentModel from '../../model/document-model';
import React from 'react';

export default function Chat({ model }: { model: DocumentModel }) {
    return <pre>
        <code>{JSON.stringify(model)}</code>
    </pre>
}

My first guess would be to make the target: "es2020" or something later than "es2015" in tsconfig.json.

But it looks like webpack is the culprit here. I googled how to stop webpack from using eval (and found some promising links:

But I bet @kerrishotts would have some ideas…

1 Like

@cpryland Thanks for your help.

It turns out: I was running webpack in development mode when not building a .xdx file (which, without Typescript, has never been a problem before). Unfortunately, this produced all those eval() calls. After running webpack --mode production, it works…

Great to know–thanks!

1 Like