使用webpack,bookmarklet-loader,style和css-loader创建bookmarklet

aru*_*mar 5 javascript bookmarklet webpack

我正在尝试使用bookmarklet-loader和style-loader和css-loader 创建一个bookmarklet .但我无法将CSS导入我的书签.

这就是我所拥有的

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'
    })
]
Run Code Online (Sandbox Code Playgroud)

SRC /书签工具/ bookmarklet.js:

import './css/style.css';

/* the rest of my bookmarklet code */
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

只需将书签添加到空白页面上的链接,我就可以将链接添加到浏览器中.

但是运行webpack会产生这个错误:

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

我尝试将以下内容添加到我的webpack.config.js:

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

这现在编译得很好,但是bookmarklet代码包含require语句,所以当我尝试在浏览器中运行它时,我得到了一个

Uncaught ReferenceError: require is not defined

我已经找到了这个这个,但一直无法让这个工作.

编辑:简单解释问题和解决方案.我正在尝试构建一个bookmarklet,但我正在使用的bookmarklet-loader用于将bookmarklet导入到其他代码段中.特别是这个bookmarklet-loader没有设置来处理bookmarklet所需的css和模板.我已经切换到使用一个简单的webpack配置生成一个已编译的javascript文件,然后使用工具将其转换为bookmarklet.

这是我的package.json,如果它对任何人的帮助:

<snip>
"scripts": {
        "build": "webpack && bookmarklet dist/index.js dist/bookmarklet.js && cat dist/bookmarklet.js | xclip -selection clipboard",
}
Run Code Online (Sandbox Code Playgroud)

现在npm run build构建书签并将其复制到我的剪贴板,以便我可以在浏览器中更新书签.

Rob*_*uez 6

我也发现这个问题很有趣,所以这里的答案仍然可以让你使用webpack来捆绑你的bookmarklet代码.

我们的想法是使用<script>标记并通过webpack将内容作为块提供:

function addScript(codeURL) {
    const scriptElement = document.createElement('script');
    scriptElement.setAttribute('src', codeURL);
    scriptElement.setAttribute('crossorigin', "anonymous");
    document.body.appendChild(scriptElement);
}
Run Code Online (Sandbox Code Playgroud)

通过一些附加的"魔法",你的index.js变为:

const add = document.createElement("a");
add.href = "javascript:(function(){s=document.createElement('script');s.type='text/javascript';s.src='bookmarklet.bundle.js';document.body.appendChild(s);})()";
add.innerHTML = "Click me";
Run Code Online (Sandbox Code Playgroud)

这是上面函数的uglified版本,它引用了你的'bookmarklet.bundle.js'块.(这样,你并不真正需要的书签装载机更多)

bookmarklet.js源(只是一个示例):

import './css/style.css';

let elements = require('./someOtherSource');

let list = document.createElement('ul');
for (let i = 0; i < elements.length; ++i) {
    let item = document.createElement('li');
    item.appendChild(document.createTextNode(elements[i]));
    list.appendChild(item);
}
document.body.appendChild(list);
Run Code Online (Sandbox Code Playgroud)

其中someOtherSource.js可以简单到:

module.exports = [ 'a', 'b', 'c'];
Run Code Online (Sandbox Code Playgroud)

最后,你的webpack.config.js变为:

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

module.exports = {
    entry: {
        index: path.resolve(__dirname, 'src/index.js'),
        bookmarklet: path.resolve(__dirname, '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: [
                    'babel-loader',
                ],
                exclude: /node_modules/,
            }
        ]
    },
    plugins: [
        new CleanWebpackPlugin(['dist']),
        new HtmlWebpackPlugin({
            title: 'Bookmarklet',
            chunks: [ "index" ],
        })
    ]
};
Run Code Online (Sandbox Code Playgroud)

同样,我在这里看到的优势是你可以使用你的webpack捆绑,css/less或其他任何加载器来构建你的书签.作为参考也见第一第二.


ghy*_*ybs 5

您在编辑中详细说明的解决方案确实是实现目标的完美有效方式.

您希望维护一个取决于注入样式的书签.

虽然您可以轻松地使用书签将标签(如<link><script>)注入到当前页面中,但它似乎不适合您的需要,因为您不需要在服务器上提供代码,并尝试链接本地资源在您的文件系统上可能不是很可靠.

因此,您希望整个代码和样式包含在bookmarklet代码中.您可以分两步进行:

  1. 将您的JS代码与内联CSS注入+ CSS的代码捆绑在一起
  2. 对包进行编码和包装,使其内容可用作书签.

1.使用内联CSS注入代码捆绑JS

对于webpack来说,这听起来很完美!实际上,它意味着捆绑您的代码并在代码中内联您的样式,style-loader就像您一样.

您甚至可以通过确保CSS中可能引用的任何其他资产(图像,Web字体等)也进行内联,使用url-loadera limit: 0始终内联这些资源来进一步推动它.

但正如你所知,你不应该使用中间假象(例如输出bookmarklet-loader),因为它们可能会遗漏一些功能(导入样式require).

您正在寻找webpack输出包:一个独立的 JavaScript代码,它将内联样式注入当前页面并执行您的代码.

2.对书签进行编码和换行

要将代码转换为书签,您必须对内容进行编码以实现URI兼容性,并添加额外的" javascript:"前缀.

这是您使用该bookmarklet包的步骤.但是,在你的情况,因为你已经是一个单一的,你要"硬编码"到书签JavaScript文件,包装是死的简单:

'javascript:' + encodeURIComponent('(function(){' + code + '})()')
Run Code Online (Sandbox Code Playgroud)

您可以继续使用bookmarklet包或使其成为一个非常简单的节点脚本(但您应该在上一步中移动缩小步骤,通常在webpack配置中).

实际上,为这个"bookmarkletify"步骤制作一个webpack插件非常容易:

function AssetToBookmarkletPlugin() {}

AssetToBookmarkletPlugin.prototype.apply = function (compiler) {
  compiler.plugin('emit', function (compilation, callback) {
    var asset;

    // Rework each asset.
    for (var assetName in compilation.assets) {
      asset = compilation.assets[assetName];
      compilation.assets[assetName] = {
        source: function () {
          // Encode and wrap the original source to make it bookmark-ready.
          return 'javascript:' + encodeURIComponent('(function(){' + asset.source() + '})()');
        },
        size: asset.size
      }
    }

    callback();
  });
};
Run Code Online (Sandbox Code Playgroud)

通过这些额外的步骤(资源内联,CSS和JS缩小,书签资产),您的webpack配置将是:

const webpack = require('webpack');
const path = require('path');

module.exports = {
  entry: {
    index: './src/index.js'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  target: 'web',
  module: {
    rules: [{
      test: /\.(png|jpg|gif)$/,
      use: [{
        loader: 'url-loader',
        options: {limit: 0} // 0 = always inline resource
      }]
    }, {
      test: /\.css$/,
      use: ['style-loader', {
        loader: 'css-loader',
        options: {minimize: true} // Minify CSS as well
      }]
    }]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin(),
    new AssetToBookmarkletPlugin()
  ]
};
Run Code Online (Sandbox Code Playgroud)

dist/index.js现在可以将文件内容复制为书签.


小智 3

我猜想 webpack bookmarklet 加载器本身不需要创建一个 bookmarklet,因为 github 存储库建议“bookmarklet-loader 是一个 webpack 加载器,它将任何 javascript 文件转换为一个 bookmarklet ,可以在整个应用程序中用作模块。 ”不清楚如果那是你的用例。

查看插件代码,

'use strict';

var uglify = require('uglify-js');

module.exports = function(source) {
  return 'module.exports = "javascript:' + encodeURIComponent(
    '(function(){'+ uglify.minify(source, { fromString: true }).code +'})();'
  ) + '"';
};
Run Code Online (Sandbox Code Playgroud)

我怀疑这个问题可能是因为这里使用的唯一包是 Uglifyjs,它只编译 javascript,代码中没有 css 加载器。该插件期望您的代码是纯 JS,而不是任何 CSS 和 HTML。

从您的代码中我看到您已经配置了 webpack 来构建 css 和 JS,并且所有这些代码为您提供的是包装在 URI 编码的函数中的 javascript uri 模式。webpack 构建输出后,DIY 应该非常简单。希望有帮助!