简体   繁体   English

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

[英]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. 我正在尝试使用bookmarklet-loader和style-loader和css-loader创建一个bookmarklet。 But I am having trouble importing css into my bookmarklet. 但我无法将CSS导入我的书签。

This is what I have 这就是我所拥有的

webpack.config.js: 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: SRC /书签工具/ bookmarklet.js:

import './css/style.css';

/* the rest of my bookmarklet code */

src/index.js: 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: 但是运行webpack会产生以下错误:

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: 我尝试将以下内容添加到我的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 这现在编译得很好,但是bookmarklet代码包含require语句,所以当我尝试在浏览器中运行它时,我得到了一个

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. 我正在尝试构建一个bookmarklet,但我正在使用的bookmarklet-loader用于将bookmarklet导入到其他代码段中。 And this bookmarklet-loader in particular is not setup to handle css and templates required by the bookmarklet. 特别是这个bookmarklet-loader没有设置来处理bookmarklet所需的css和模板。 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. 我已经切换到使用一个简单的webpack配置生成一个已编译的javascript文件,然后使用工具将其转换为bookmarklet。

This is my package.json in case if its of help to anyone: 这是我的package.json,如果它对任何人的帮助:

<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. 现在npm run build构建了bookmarklet并将其复制到我的剪贴板,以便我可以在浏览器中更新bookmarklet。

I've also found this question interesting so here's an answer that would still let you use webpack for bundling your bookmarklet code. 我也发现这个问题很有趣,所以这里的答案仍然可以让你使用webpack来捆绑你的bookmarklet代码。

The idea is to use a <script> tag and serve the content as a chunk through webpack: 我们的想法是使用<script>标记并通过webpack将内容作为块提供:

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

With some aditional 'magic', your index.js becomes: 通过一些附加的“魔法”,你的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";

which is the uglified version of the above function that references your 'bookmarklet.bundle.js' chunk. 这是上面函数的uglified版本,它引用了你的'bookmarklet.bundle.js'块。 (this way you don't really need the bookmarklet-loader any more) (这样你就不再需要bookmarklet-loader)

The bookmarklet.js source (just a sample): 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);

where someOtherSource.js could be as simple as: 其中someOtherSource.js可以简单到:

module.exports = [ 'a', 'b', 'c'];

and finally, your webpack.config.js becomes: 最后,你的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" ],
        })
    ]
};

Again, the advantage I see here is that you get to use your webpack bundling, css/less or whatever other loaders for building your bookmarklet. 同样,我在这里看到的优势是你可以使用你的webpack捆绑,css / less或其他任何加载器来构建你的书签。 As reference also see first and second . 作为参考也见第一第二

The solution you detail in your edit is indeed a perfectly valid way of achieving your objective. 您在编辑中详细说明的解决方案确实是实现目标的完美有效方式。

You want to maintain a bookmarklet that depends on injecting styles. 您希望维护一个取决于注入样式的书签

While you can easily inject tags (like <link> and <script> ) with a bookmarklet to load external resources into the current page, it does not seem to fit your need because you do not need to make your code available on a server, and trying to link local resources on your file system might not be very reliable. 虽然您可以轻松地将标签(如<link><script> )注入书签以将外部资源加载到当前页面,但它似乎不适合您的需要,因为您不需要在服务器上提供代码,并尝试链接文件系统上的本地资源可能不太可靠。

Therefore you would like the entire code and styles to be contained within the bookmarklet code. 因此,您希望整个代码和样式包含在bookmarklet代码中。 You can proceed in 2 steps: 您可以分两步进行:

  1. Bundle your JS code with code for inline CSS injection + CSS 将您的JS代码与内联CSS注入+ CSS的代码捆绑在一起
  2. Encode and wrap the bundle so that its content can be used as a bookmark. 对包进行编码和包装,使其内容可用作书签。

1. Bundle JS with code for inline CSS injection 1.使用内联CSS注入代码捆绑JS

This sounds like a perfect job for webpack! 对于webpack来说,这听起来很完美! Indeed it is meant to bundle your code and inline your styles within the code as well, with style-loader like you did. 实际上它意味着捆绑你的代码并在代码中内联你的样式,就像你一样使用style-loader

You could even push it slightly further by making sure any other asset (image, web font, etc.) that is potentially referred to in your CSS is also inlined, using url-loader with a limit: 0 to always inline those resources. 您甚至可以通过确保CSS中可能引用的任何其他资产(图像,Web字体等)也进行内联,使用带有limit: 0 url-loader limit: 0来始终内联这些资源。

But as you figured out, you should not use the intermediate artefacts (like for example the output from bookmarklet-loader ), since they will likely miss some functionalities (importing style, require ). 但正如你所知,你不应该使用中间假象(例如来自bookmarklet-loader的输出),因为它们可能会遗漏一些功能(导入样式, require )。

The webpack output bundle is what you are looking for: a standalone JavaScript code that injects inline styles into the current page and executes your code. 您正在寻找webpack输出包:一个独立的 JavaScript代码,它将内联样式注入当前页面并执行您的代码。

2. Encode and wrap for bookmark 2.对书签进行编码和换行

To convert the code into a bookmarklet, you have to encode the content for URI compatibility, and add an extra " javascript: " prefix. 要将代码转换为书签,您必须对内容进行编码以实现URI兼容性,并添加额外的“ javascript: ”前缀。

This is the step where you have used the bookmarklet package. 这是您使用bookmarklet包的步骤。 But in your case, since all you have is a single JavaScript file that you want to "hard code" into the bookmarklet, the wrapper is dead simple: 但是,在你的情况,因为你已经是要“硬编码”到书签一个 JavaScript文件,该包装是死的简单:

'javascript:' + encodeURIComponent('(function(){' + code + '})()')

You can continue using bookmarklet package or make it a very simple node script (but you should move the minification step in a previous step, typically in the webpack configuration). 您可以继续使用bookmarklet包或使其成为一个非常简单的节点脚本(但您应该在上一步中移动缩小步骤,通常在webpack配置中)。

Actually, it is quite easy to make a webpack plugin for this "bookmarkletify" step: 实际上,为这个“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();
  });
};

With these additional steps (resources inlining, CSS and JS minification, bookmarkletify assets), your webpack configuration would be: 通过这些额外的步骤(资源内联, 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()
  ]
};

The content of dist/index.js file is now ready to be copied as a bookmark. 现在可以将dist/index.js文件的内容复制为书签。

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. 我猜想webpack bookmarklet加载器本身并不需要创建一个bookmarklet,因为github repo建议“bookmarklet-loader是一个webpack加载器,它可以将任何javascript文件转换为可在整个应用程序中用作模块的书签 ”不清楚如果那是你的用例。

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. 我怀疑问题可能是因为这里使用的唯一包是Uglifyjs,它只编译javascript,代码中没有css加载器。 This plugin expects your code to be pure JS and not any CSS and HTML. 这个插件希望你的代码是纯JS而不是任何CSS和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. 从您的代码中我看到您已经配置了webpack来构建css和JS,并且所有这些代码都提供了javascript uri模式包装在一个URI编码的函数中。 should be pretty simple to DIY after the webpack build output. 在webpack构建输出后,DIY应该非常简单。 hope that helps! 希望有所帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM