Login Register
Back to Help Center

Using Third-Party Libraries

How to bundle external JavaScript and CSS libraries inside a plugin, and why CDN links do not work

Plugins run inside a sandboxed iframe from an opaque origin — the browser treats the plugin as if it has no origin at all. This means that <script> tags pointing to external CDN URLs will fail with a CORS error:

<!-- ❌ This will fail — CORS blocks cross-origin scripts from an opaque origin -->
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

The browser blocks the request because the opaque origin cannot satisfy the CDN's CORS policy.

Do not use CDN links for any JavaScript or CSS in your plugin. All external libraries must be downloaded and bundled inside the plugin directory in your ZIP.

How to Bundle a Third-Party Library

The solution is straightforward: download the library's minified build and place it alongside your index.html in the plugin directory.

Step 1 — Download the library

Download the minified .js (and .css if needed) file from the library's releases page, npm, or CDN. For example, for Chart.js:

Step 2 — Place it in your plugin directory

plugins/
  my-chart/
    index.html
    script.js
    chart.umd.min.js    ← Bundled library
    monkeyCodeInput.js  ← Auto-injected, no need to include

Step 3 — Reference it with a relative path

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <script src="./monkeyCodeInput.js"></script>
  <script src="./chart.umd.min.js"></script>  <!-- ✅ Relative path -->
  <script src="./script.js"></script>
</head>
<body>
  <canvas id="myChart" width="380" height="360"></canvas>
</body>
</html>

Full Example: Chart.js Bar Chart

This example reads a list of numbers from the sample input and renders them as a bar chart using Chart.js.

Plugin directory structure:

plugins/
  bar-chart/
    index.html
    chart.umd.min.js    ← Downloaded from Chart.js releases

index.html:

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="./monkeyCodeInput.js"></script>
  <script src="./chart.umd.min.js"></script>
  <style>
    body { margin: 0; display: flex; align-items: center; justify-content: center; height: 100vh; }
  </style>
</head>
<body>
  <canvas id="chart" width="380" height="360"></canvas>
  <script>
    // Read input: first line is n, second line is n space-separated integers
    const lines = inputLines()
    const n = parseInt(lines[0])
    const values = lines[1].split(' ').map(Number)

    const labels = values.map((_, i) => `Item ${i + 1}`)

    new Chart(document.getElementById('chart'), {
      type: 'bar',
      data: {
        labels,
        datasets: [{
          label: 'Values',
          data: values,
          backgroundColor: '#6366f1',
          borderRadius: 4,
        }]
      },
      options: {
        responsive: false,
        plugins: { legend: { display: false } },
        scales: { y: { beginAtZero: true } }
      }
    })
  </script>
</body>
</html>

Problem statement reference:

problem.en.tex
\plugin{bar-chart}

Sample input format:

5
3 1 4 1 5

Tips for Keeping Bundle Size Small

The entire problem package must be under 50 MB. When bundling libraries:

  • Use the minified (.min.js) build, not the development build
  • Prefer UMD or IIFE builds that expose a global variable — these work without a module bundler
  • If a library has optional modules, only include what you need
  • Consider lightweight alternatives (e.g. uPlot instead of Chart.js for line charts, Cytoscape.js for graphs)

CSS Libraries

The same rule applies to CSS frameworks. Download the stylesheet and reference it locally:

plugins/
  styled-viz/
    index.html
    normalize.min.css   ← Downloaded locally
    script.js
index.html
<link rel="stylesheet" href="./normalize.min.css">