Skip to content

Instantly share code, notes, and snippets.

@thejohnfreeman
Last active January 5, 2023 02:15
Show Gist options
  • Save thejohnfreeman/563337119e20d090ea2d22bee9b05a6b to your computer and use it in GitHub Desktop.
Save thejohnfreeman/563337119e20d090ea2d22bee9b05a6b to your computer and use it in GitHub Desktop.
Semantic UI fonts with Webpack in a Chrome extension

To get Semantic UI fonts working:

  1. npm install semantic-ui-css

  2. Import 'semantic-ui-css/semantic.css' in your entry script. The exact syntax for this varies depending on your chosen module format: import for ES6, require for CommonJS, etc. This tells Webpack to pull the CSS into your bundle.

  3. npm install --save-dev style-loader css-loader

  4. Use css-loader in your Webpack configuration:

    // webpack.config.js
    module: {
      loaders: [
        { test: /\.css$/, loaders: ['style', 'css'] }
      ]
    }

    This tells Webpack how to handle your import of the CSS. When css-loader parses the CSS, it will find references to the required fonts.

  5. npm install --save-dev file-loader url-loader

    file-loader is a peer dependency of url-loader.

  6. Add loaders for the fonts to your Webpack configuration:

    // webpack.config.js
    module: {
      loaders: [
        {
          test: /\.(eot|png|svg|[ot]tf|woff2?)(\?v=\d+\.\d+\.\d+)?$/,
          loader: 'url',
          query: {limit: 10000}
        }
      ]
    }

    This will put your fonts in the bundle if they're smaller than 10kb. Otherwise they'll be referenced by URL. Since the fonts will be packaged in your extension, they need a base URL of chrome.extension.getURL(''). The base URL for Webpack imports can be controlled with the output.publicPath option in your Webpack configuration, but we can't know the extension's base URL at build time because it isn't generated until the extension is added to Chrome. We can modify the base URL for Webpack imports at runtime in one way: assigning the value of __webpack_public_path__ in a separate module at the beginning of our entry's module list.

Note: it is not sufficient to assign __webpack_public_path__ in a separate file at the beginning of our extension's content_script's js list. It will be reset by our bundle's Webpack bootstrap.

  1. Create a new module:

    // configure-webpack.js
    __webpack_public_path__ = chrome.extension.getURL('')

    The variable assigned must be exactly __webpack_public_path__, not window.__webpack_public_path__ or anything else.

  2. Add the module to the beginning of your entry's module list:

    // webpack.config.js
    entry: ['configure-webpack', ...]
  3. You might need to adjust Webpack's resolve settings so that it can find the module:

In particular, if the file configure-webpack.js sits next to webpack.config.js:

// webpack.config.js
resolve: { root: __dirname }
  1. Let your content script access the fonts that exist as separate files in your extension and weren't packaged in the Webpack bundle (thanks to Aleksandr Motsjonov for pointing this out!):
// manifest.json
"web_accessible_resources": [
  "*.png",
  "*.eot",
  "*.woff",
  "*.woff2",
  "*.ttf",
  "*.svg"
]
@fduayer
Copy link

fduayer commented Oct 29, 2019

Holy shit! This was awesome!
Worked out perfectly! Thanks

@fduayer
Copy link

fduayer commented Nov 1, 2019

However, it doesn't seem to work with the Mini-Css-Extract-Plugin
Any thoughts??

@cameck
Copy link

cameck commented Mar 3, 2021

Thank you 🙇

@Apollinaire
Copy link

Apollinaire commented Apr 13, 2021

input #7 breaks firefox content-scripts. It can be fixed by removing the window, since window.chrome does not exist on firefox but chrome does.

// configure-webpack.js
__webpack_public_path__ = chrome.extension.getURL('')

This is still working on chrome obviously

@cameck
Copy link

cameck commented Apr 13, 2021

input #7 breaks firefox content-scripts. It can be fixed by removing the window, since window.chrome does not exist on firefox but chrome does.

// configure-webpack.js
__webpack_public_path__ = chrome.extension.getURL('')

This is still working on chrome obviously

I think you still want Firefox though? You can do something like this before getting the URL:
window.chrome = window.chrome || window.browser;

Also, side note window.chrome.extension.getURL('') is deprecated, best to update to window.chrome.runtime.getURL('')

@thejohnfreeman
Copy link
Author

Are you sure it won't work? Mozilla says:

Note that this is different from Google Chrome's extension system, which uses the chrome namespace instead of browser, and which uses callbacks instead of promises for asynchronous functions. As a porting aid, the Firefox implementation of WebExtensions APIs supports chrome and callbacks as well as browser and promises. This allows code written for Chrome to run largely unchanged in Firefox for the APIs documented here.

Regardless, should (window.chrome || window.browser).runtime.getURL('') work for both?

@Apollinaire
Copy link

My main point is that on FF the chrome key is not set on window, to access it you just use the global chrome variable.
So chrome.runtime.getUrl('') works for both, but window.chrome.runtime.getUrl('') will throw "cannot get runtime of undefined` for me on FF

@thejohnfreeman
Copy link
Author

Ok, but is window.browser set in Firefox too? That's the variable Mozilla documents. chrome might be an undocumented variable that could disappear in any version, or it might be set by a dependency of yours that not everyone will have.

@Apollinaire
Copy link

The chrome variable is documented here for Firefox. They do support window.browser... but Chrome does not.
The page linked above documents the incompatibilities between Chrome & Firefox. Basically, Chrome supports chrome and window.chrome, with callback APIs, and Firefox supports browser, window.browser with Promise APIs, and they have chrome with callback APIs, but not window.chrome. So the only fully cross-browser way is just using the global chrome (unless you have a build system with a polyfill, but that's probably out of the scope of that gist)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment