How to Import Javascript Module from external javascript file into <script> tag of HTML file
Asked Answered
S

4

3

I am trying to import a module called 'JSZip' from an external node package called JSZip in my HTML File.

Importing it directly using import command is not working,

<script>    

     import JSZip from '../node_modules/jszip/dist/jszip.min.js';

</script>

I also tried importing it in HTML file in the script tag

<script type="text/javascript" src="node_modules/jszip/dist/jszip.min.js"></script>

But the above code is still not importing the module.

I understand this can be easily achieved if we do it directly in a javascript file, but I am building this for a figma plugin and I am constrained to do this on ui.html file because the browser APIs can be only called on the html side and the js file runs in another sandbox environment.

To read more about figma plugin's ui and js files, you can refer this

Thanks in advance for any help :)

Sopher answered 7/7, 2020 at 20:30 Comment(2)
I'd expect the first approach to fail with an obvious error message, and the latter approach to work. How are you determining that it isn't working? What have you don't do debug it? Are errors listed on the Console? Does the Network tab show it successfully loading with the content you expect and not HTTP error?Twotone
See Moz guide on JS modules and https://mcmap.net/q/167492/-es2015-import-doesn-39-t-work-even-at-top-level-in-firefox.Formication
U
2

Either import the module with <script type="module"> (see compatibility chart)...

Or, for IE & other old browsers support, use Babel or similar and compile all your JS into a single, minified and ES5 compatible (the old javascript) file.

Upthrow answered 7/7, 2020 at 20:35 Comment(4)
Can the downvoter please explain what is wrong with my answer?Wivinah
Doesn't work for me: I get "Uncaught TypeError: Failed to resolve module specifier "/ui.js" Invalid relative url or base scheme isn't hierarchical." if im trying to import a script "ui.js" in the same directory as ui.html being in the manifest. In the network tab of the figma web developer console I see that ui.html ism't directly loaded, instead they create a data/text: html request for ui.html. My guess is: simply not possible in the figma plugin context.Pyrite
@Leo, try "./ui.js" instead of "/ui.js"Wivinah
@odeltazero thanks, tried that too but it is written in the figma docs that none of that works. You have to use a tool like webpack to inline all scripts in the html page. Will post my webpack config here.Pyrite
C
2

add type="module" to script tag. it will work.

<script type="module">    
     import JSZip from '../node_modules/jszip/dist/jszip.min.js';
</script>
Crustaceous answered 7/7, 2020 at 20:49 Comment(0)
C
0

It's best to use webpack in this case. You get the benefit of using js imports and create small modules for your code. But when it's time to execute it, wepback will convert all that, into one single js file.

Make sure you have a package.json file that has "type": "module" and in your code you can import other js files with import Foo from './Foo.js' while the js files have export default { }

// file - package.json

{
  "type": "module"
}

// file - index.js

import Foo from './Foo.js'

Foo.start()

// file - Foo.js

export default {
  start () {
    console.log('start')
  }
}

// file - webpack.config.cjs

return {
  target: 'web',
  entry: './index.js',
  output: './script.js'
}
<script src="script.js"></script>
Cinderellacindi answered 14/5, 2021 at 7:5 Comment(0)
P
0

As I couldn't find in the figma docs a way how to produce a html from a ui.html template including a ui.js(which is created by webpack from a ui.ts) here my webpack config. You need to install also the html-webpack-plugin (see https://webpack.js.org/plugins/html-webpack-plugin/ ) in order to create html pages from a template.

Note I used that to develop a plugin for the figma desktop app. May be the other suggestions in this topic work for plugins loaded in the browser...I can't tell that for now. In any case the <script type="module"> suggestion didn't work for me: the module simply wasn't requested in the network tab. (And the electron desktop browser loads the ui.html page as a data:text/html;base64 blob, so it should be clear that this is not a normal http server access of ui.html .)

//webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = (env, argv) => ({
mode: argv.mode === 'production' ? 'production' : 'development',

// This is necessary because Figma's 'eval' works differently than normal eval
devtool: argv.mode === 'production' ? false : 'inline-source-map',
  entry: {
    code: './src/code.ts', // This is the entry point for our plugin code running in the figma context.
    ui: './src/ui.ts' // This is the entry point for the ui code running in the context of ui.html.
  },
  module: {
    rules: [
      // Converts TypeScript code to JavaScript
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      }
      //,{ test: /\.pug$/, loader: "pug-loader", exclude: /node_modules/ } //use that if you have a .pug template
    ],
  },
  // Webpack tries these extensions for you if you omit the extension like "import './file'"
  resolve: {
    extensions: ['.ts', '.js'],
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist') //output is in the 'dist/' dir
  },
  plugins: [
   new HtmlWebpackPlugin({
      title: 'My First Figma Plugin',
      filename: 'ui.html', //produces a 'dist/ui.html' file
      template: 'src/uitempl.html' //use a template file
    })
  ]
});
      

The template file

<!--src/uitempl.html-->
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
    <h2>My Exporter</h2>
    <button id="export">Export</button>
    <button id="cancel">Cancel</button>
    <script><%= compilation.assets["ui.js"].source() %></script>
  </body>
</html>

The htmlWebpackPlugin uses some magic markers to inject title and source code. So for example <%= compilation.assets["ui.js"].source() %> is replaced with the source code of ui.js.

Pyrite answered 5/6 at 22:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.