簡體   English   中英

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

[英]Creating a bookmarklet using webpack, bookmarklet-loader, style and css-loader

我正在嘗試使用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'
    })
]

SRC /書簽工具/ 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);

只需將書簽添加到空白頁面上的鏈接,我就可以將鏈接添加到我的瀏覽器中。

但是運行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')
}

這現在編譯得很好,但是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",
}

現在npm run build構建了bookmarklet並將其復制到我的剪貼板,以便我可以在瀏覽器中更新bookmarklet。

我也發現這個問題很有趣,所以這里的答案仍然可以讓你使用webpack來捆綁你的bookmarklet代碼。

我們的想法是使用<script>標記並通過webpack將內容作為塊提供:

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

通過一些附加的“魔法”,你的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";

這是上面函數的uglified版本,它引用了你的'bookmarklet.bundle.js'塊。 (這樣你就不再需要bookmarklet-loader)

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);

其中someOtherSource.js可以簡單到:

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

最后,你的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" ],
        })
    ]
};

同樣,我在這里看到的優勢是你可以使用你的webpack捆綁,css / less或其他任何加載器來構建你的書簽。 作為參考也見第一第二

您在編輯中詳細說明的解決方案確實是實現目標的完美有效方式。

您希望維護一個取決於注入樣式的書簽

雖然您可以輕松地將標簽(如<link><script> )注入書簽以將外部資源加載到當前頁面,但它似乎不適合您的需要,因為您不需要在服務器上提供代碼,並嘗試鏈接文件系統上的本地資源可能不太可靠。

因此,您希望整個代碼和樣式包含在bookmarklet代碼中。 您可以分兩步進行:

  1. 將您的JS代碼與內聯CSS注入+ CSS的代碼捆綁在一起
  2. 對包進行編碼和包裝,使其內容可用作書簽。

1.使用內聯CSS注入代碼捆綁JS

對於webpack來說,這聽起來很完美! 實際上它意味着捆綁你的代碼並在代碼中內聯你的樣式,就像你一樣使用style-loader

您甚至可以通過確保CSS中可能引用的任何其他資產(圖像,Web字體等)也進行內聯,使用帶有limit: 0 url-loader limit: 0來始終內聯這些資源。

但正如你所知,你不應該使用中間假象(例如來自bookmarklet-loader的輸出),因為它們可能會遺漏一些功能(導入樣式, require )。

您正在尋找webpack輸出包:一個獨立的 JavaScript代碼,它將內聯樣式注入當前頁面並執行您的代碼。

2.對書簽進行編碼和換行

要將代碼轉換為書簽,您必須對內容進行編碼以實現URI兼容性,並添加額外的“ javascript: ”前綴。

這是您使用bookmarklet包的步驟。 但是,在你的情況,因為你已經是要“硬編碼”到書簽一個 JavaScript文件,該包裝是死的簡單:

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

您可以繼續使用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();
  });
};

通過這些額外的步驟(資源內聯, 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()
  ]
};

現在可以將dist/index.js文件的內容復制為書簽。

我猜想webpack bookmarklet加載器本身並不需要創建一個bookmarklet,因為github repo建議“bookmarklet-loader是一個webpack加載器,它可以將任何javascript文件轉換為可在整個應用程序中用作模塊的書簽 ”不清楚如果那是你的用例。

看看插件代碼,

'use strict';

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

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

我懷疑問題可能是因為這里使用的唯一包是Uglifyjs,它只編譯javascript,代碼中沒有css加載器。 這個插件希望你的代碼是純JS而不是任何CSS和HTML。

從您的代碼中我看到您已經配置了webpack來構建css和JS,並且所有這些代碼都提供了javascript uri模式包裝在一個URI編碼的函數中。 在webpack構建輸出后,DIY應該非常簡單。 希望有所幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM