Search code examples
javascriptwebpackbookmarklet

Creating a bookmarklet using webpack, bookmarklet-loader, style and css-loader


I am trying to create a bookmarklet using bookmarklet-loader and the style-loader and css-loader. But I am having trouble importing css into my bookmarklet.

This is what I have

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
entry: {
    index: './src/index.js',
    bookmarklet: './src/bookmarklets/bookmarklet.js'
},
output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, 'dist')
},
target: 'web',
module: {
    rules: [
    {
        test: /\.css$/,
        use: [
            'style-loader',
            'css-loader'
        ]
    },
    {
        test: /\.js$/,
        use: [
           'bookmarklet-loader'
        ],
        include: path.join(__dirname, './src/bookmarklets')
    }
    ]
},
plugins: [
    new CleanWebpackPlugin(['dist']),
    new HtmlWebpackPlugin({
        title: 'Development'
    })
]

src/bookmarklets/bookmarklet.js:

import './css/style.css';

/* the rest of my bookmarklet code */

src/index.js:

import bookmarklet from './bookmarklets/bookmarklet';

var add = document.createElement("a");
add.href = "javascript:" + bookmarklet;
add.innerHTML = "Click me";

document.body.appendChild(add);

Simply adds the bookmarklet to a link on a blank page, so I can add the link to my browser.

But running webpack produces this error:

SyntaxError: Unexpected token: string (./css/style.css) at [snipped] node_modules/uglify-js/tools/node.js

I tried adding the following to my webpack.config.js:

{
    test: /\.js$/,
    use: [
       'bookmarklet-loader',
       'style-loader',
       'css-loader'
    ],
    include: path.join(__dirname, './src/bookmarklets')
}

This now compiles fine, but the bookmarklet code contains require statements so when I try and run it in the browser I get an

Uncaught ReferenceError: require is not defined

I have found this and this but have been unable to get this to work.

Edit: To explain simply the question and solution. I am trying to build a bookmarklet, but the bookmarklet-loader I am using is used for importing bookmarklets into other pieces of code. And this bookmarklet-loader in particular is not setup to handle css and templates required by the bookmarklet. I have switched to using a simple webpack config that produces a compiled javascript file and then this tool to convert that to a bookmarklet.

This is my package.json in case if its of help to anyone:

<snip>
"scripts": {
        "build": "webpack && bookmarklet dist/index.js dist/bookmarklet.js && cat dist/bookmarklet.js | xclip -selection clipboard",
}

Now npm run build builds the bookmarklet and copies it to my clipboard so I can update the bookmarklet in the browser.


Solution

  • I guess webpack bookmarklet loader is not required to create a bookmarklet itself, as the github repo suggests "bookmarklet-loader is a webpack loader that will convert any javascript file into a bookmarklet that can be used as a module throughout your application." Not clear if thats your use case.

    looking at the plugin code,

    'use strict';
    
    var uglify = require('uglify-js');
    
    module.exports = function(source) {
      return 'module.exports = "javascript:' + encodeURIComponent(
        '(function(){'+ uglify.minify(source, { fromString: true }).code +'})();'
      ) + '"';
    };
    

    i suspect the issue could be because the only package used here is Uglifyjs which only compiles javascript, and no css loaders in the code. This plugin expects your code to be pure JS and not any CSS and HTML.

    From your code i see that you have configured webpack already to build css and JS, and all this code is offering you is javascript uri pattern wrapped in a function that is URI encoded. should be pretty simple to DIY after the webpack build output. hope that helps!