使用 webpack、bookmarklet-loader、style 和 css-loader 创建书签
Creating a bookmarklet using webpack, bookmarklet-loader, style and css-loader
我正在尝试使用 bookmarklet-loader 和 style-loader 以及 css-loader 创建一个小书签。但是我无法将 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/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);
只需将小书签添加到空白页上的 link,这样我就可以将 link 添加到我的浏览器中。
但是 运行ning 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')
}
现在可以正常编译,但是小书签代码包含 require 语句,所以当我在浏览器中尝试 运行 它时,我得到一个
Uncaught ReferenceError: require is not defined
编辑:
简单解释问题和解决方案。我正在尝试构建一个小书签,但我使用的小书签加载器用于将小书签导入其他代码段。特别是这个小书签加载器没有设置为处理 css 和小书签所需的模板。我已经切换到使用一个简单的 webpack 配置,它生成一个编译的 javascript 文件,然后 this 工具将其转换为书签。
这是我的 package.json 如果它对任何人有帮助:
<snip>
"scripts": {
"build": "webpack && bookmarklet dist/index.js dist/bookmarklet.js && cat dist/bookmarklet.js | xclip -selection clipboard",
}
现在 npm run build
构建小书签并将其复制到我的剪贴板,以便我可以在浏览器中更新小书签。
我想 webpack 书签加载器不需要自己创建书签,正如 github 仓库建议的那样
"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."
不清楚这是否是您的用例。
查看插件代码,
'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 应该非常简单。
希望对您有所帮助!
我也发现这个问题很有趣,所以这里的答案仍然可以让您使用 webpack 来捆绑您的小书签代码。
这个想法是使用 <script>
标签并通过 webpack 将内容作为一个块提供:
function addScript(codeURL) {
const scriptElement = document.createElement('script');
scriptElement.setAttribute('src', codeURL);
scriptElement.setAttribute('crossorigin', "anonymous");
document.body.appendChild(scriptElement);
}
有了一些额外的 'magic',您的 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";
这是上述函数的丑化版本,它引用了您的 '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 或任何其他加载程序来构建您的小书签。作为参考,另见 first and second.
您在编辑中详述的解决方案确实是实现您的 objective.
的完全有效方式
您想维护一个依赖注入样式的 bookmarklet。
虽然您可以使用小书签轻松地注入标签(如 <link>
和 <script>
)以将外部资源加载到当前页面,但它似乎不符合您的需要,因为您不需要使您的代码在服务器上可用,并尝试 link 文件系统上的本地资源可能不是很可靠。
因此,您希望整个代码和样式包含在小书签代码中。您可以分两步进行:
- 将您的 JS 代码与内联 CSS 注入代码捆绑在一起 + CSS
- 对捆绑包进行编码和包装,使其内容可用作书签。
1.将 JS 与内联代码捆绑 CSS 注入
这听起来像是 webpack 的完美工作!事实上,它的目的是捆绑您的代码并在代码中内联您的样式,就像您所做的那样 style-loader
。
你甚至可以通过确保你的 CSS 中可能引用的任何其他资产(图像、网络字体等)也被内联,使用 url-loader
来进一步推动它a limit: 0
始终内联这些资源。
但是正如您发现的那样,您不应该使用中间人工制品(例如 bookmarklet-loader
的输出),因为它们可能会遗漏一些功能(导入样式,require
)。
webpack 输出包就是您要查找的内容:独立 JavaScript 将内联样式注入当前页面并执行您的代码的代码。
2。为书签编码和换行
要将代码转换为小书签,您必须对内容进行编码以实现 URI 兼容性,并添加额外的“javascript:
”前缀。
这是您使用 bookmarklet
包的步骤。但是在你的情况下,因为你只有一个 single JavaScript 文件,你想 "hard code" 进入书签,包装器非常简单:
'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
文件的内容复制为书签。
我正在尝试使用 bookmarklet-loader 和 style-loader 以及 css-loader 创建一个小书签。但是我无法将 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/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);
只需将小书签添加到空白页上的 link,这样我就可以将 link 添加到我的浏览器中。
但是 运行ning 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')
}
现在可以正常编译,但是小书签代码包含 require 语句,所以当我在浏览器中尝试 运行 它时,我得到一个
Uncaught ReferenceError: require is not defined
编辑: 简单解释问题和解决方案。我正在尝试构建一个小书签,但我使用的小书签加载器用于将小书签导入其他代码段。特别是这个小书签加载器没有设置为处理 css 和小书签所需的模板。我已经切换到使用一个简单的 webpack 配置,它生成一个编译的 javascript 文件,然后 this 工具将其转换为书签。
这是我的 package.json 如果它对任何人有帮助:
<snip>
"scripts": {
"build": "webpack && bookmarklet dist/index.js dist/bookmarklet.js && cat dist/bookmarklet.js | xclip -selection clipboard",
}
现在 npm run build
构建小书签并将其复制到我的剪贴板,以便我可以在浏览器中更新小书签。
我想 webpack 书签加载器不需要自己创建书签,正如 github 仓库建议的那样 "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." 不清楚这是否是您的用例。
查看插件代码,
'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 应该非常简单。 希望对您有所帮助!
我也发现这个问题很有趣,所以这里的答案仍然可以让您使用 webpack 来捆绑您的小书签代码。
这个想法是使用 <script>
标签并通过 webpack 将内容作为一个块提供:
function addScript(codeURL) {
const scriptElement = document.createElement('script');
scriptElement.setAttribute('src', codeURL);
scriptElement.setAttribute('crossorigin', "anonymous");
document.body.appendChild(scriptElement);
}
有了一些额外的 'magic',您的 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";
这是上述函数的丑化版本,它引用了您的 '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 或任何其他加载程序来构建您的小书签。作为参考,另见 first and second.
您在编辑中详述的解决方案确实是实现您的 objective.
的完全有效方式您想维护一个依赖注入样式的 bookmarklet。
虽然您可以使用小书签轻松地注入标签(如 <link>
和 <script>
)以将外部资源加载到当前页面,但它似乎不符合您的需要,因为您不需要使您的代码在服务器上可用,并尝试 link 文件系统上的本地资源可能不是很可靠。
因此,您希望整个代码和样式包含在小书签代码中。您可以分两步进行:
- 将您的 JS 代码与内联 CSS 注入代码捆绑在一起 + CSS
- 对捆绑包进行编码和包装,使其内容可用作书签。
1.将 JS 与内联代码捆绑 CSS 注入
这听起来像是 webpack 的完美工作!事实上,它的目的是捆绑您的代码并在代码中内联您的样式,就像您所做的那样 style-loader
。
你甚至可以通过确保你的 CSS 中可能引用的任何其他资产(图像、网络字体等)也被内联,使用 url-loader
来进一步推动它a limit: 0
始终内联这些资源。
但是正如您发现的那样,您不应该使用中间人工制品(例如 bookmarklet-loader
的输出),因为它们可能会遗漏一些功能(导入样式,require
)。
webpack 输出包就是您要查找的内容:独立 JavaScript 将内联样式注入当前页面并执行您的代码的代码。
2。为书签编码和换行
要将代码转换为小书签,您必须对内容进行编码以实现 URI 兼容性,并添加额外的“javascript:
”前缀。
这是您使用 bookmarklet
包的步骤。但是在你的情况下,因为你只有一个 single JavaScript 文件,你想 "hard code" 进入书签,包装器非常简单:
'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
文件的内容复制为书签。