[英]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.使用內聯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.