如何将多个静态文件捆绑为 zip 存档以供下载
How to bundle multiple static files as zip archive for download
我的 Jekyll 页面旨在为编码书籍的练习提供示例解决方案。
解决方案是一堆 .cpp 文件(C++ 代码文件)存储在我的 Jekyll 项目中的一个文件夹中,这样我就可以在 IDE.
中打开同一个文件夹
我已经设法为每本书的章节自动生成一页,将相关解决方案显示为代码块列表(每个练习一个)。我通过遍历 site.static_files
并通过文件名中的数字识别文件来做到这一点(例如,第 1 章的两个解决方案:01_1_FirstSolution.cpp
、01_2_SecondSolution.cpp
)
现在,我还想为每本书的章节提供一个 zip 存档,其中包含相关的 .cpp 文件。我不想手动制作 zip 文件,因为那样我将无法再简单地更改其中一个代码文件。理想情况下,我想在循环 site.static_files
并过滤相关文件的同时构建一个 zip 文件。
我搜索这个的时候,主要是找到了一些速度优化插件,用于打包和压缩资源。我是 运行 Jekyll Windows。
Jekyll 主要是静态网站构建器,因此在使用 Jekyll 构建之前 运行 一个程序或 shell 脚本并将它们输出到 site.static_files
可能是理想的选择您希望输出到的位置如上。
您可以在 运行ning Jekyll 之前使用脚本来压缩您的文件,然后 运行 Jekyll 构建过程。
还有 Generator plugins 您可以使用插件或 Ruby 对 运行 脚本的 system
命令来实现类似的结果你的构建。
如果可以获取文件内容(fetch etc.) you may use JSZip 库将它们打包成 Zip。我不确定这是否适合你在 jekyll 中...但我会尝试这样做。
要尝试示例,只需创建一个 html 文件或 open my example with fetch。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js" integrity="sha512-uVSVjE7zYsGz4ag0HEzfugJ78oHCI1KhdkivjQro8ABL/PRiEO4ROwvrolYAcZnky0Fl/baWKYilQfWvESliRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js" integrity="sha512-csNcFYJniKjJxRWRV1R7fvnXrycHP6qDR21mgz1ZP55xY5d+aHLfo9/FcGDQLfn2IfngbAHd8LdfsagcCqgTcQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<script>
var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");
zip.file("Hello2.txt", "Hello2 World\n");
//var img = zip.folder("images");
//img.file("smile.gif", imgData, {base64: true});
zip.generateAsync({type:"blob"})
.then((content) => {
// see FileSaver.js
saveAs(content, "example.zip");
});
</script>
</body>
</html>
有 jekyll-zip-bundler 插件。
如何使用
作为多个参数的文件名:
{% zip archiveToCreate.zip file1.txt file2.txt %}
文件名中的空格:
{% zip archiveToCreate.zip file1.txt folder/file2.txt 'file with spaces.txt' %}
包含文件列表的变量也是可能的:
{% zip ziparchiveToCreate.zip {{ chapter_code_files }} %}
插件代码
# frozen_string_literal: true
# Copyright 2021 by Philipp Hasper
# MIT License
# https://github.com/PhilLab/jekyll-zip-bundler
require 'jekyll'
require 'zip'
# ~ gem 'rubyzip', '~>2.3.0'
module Jekyll
# Valid syntax:
# {% zip archiveToCreate.zip file1.txt file2.txt %}
# {% zip archiveToCreate.zip file1.txt folder/file2.txt 'file with spaces.txt' %}
# {% zip {{ variableName }} file1.txt 'folder/file with spaces.txt' {{ otherVariableName }} %}
# {% zip {{ variableName }} {{ VariableContainingAList }} %}
class ZipBundlerTag < Liquid::Tag
VARIABLE_SYNTAX = /[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)/mx.freeze
CACHE_FOLDER = '.jekyll-cache/zip_bundler/'
def initialize(tag_name, markup, tokens)
super
# Split by spaces but only if the text following contains an even number of '
# Based on
# Extended to also not split between the curly brackets of Liquid
# In addition, make sure the strings are stripped and not empty
@files = markup.strip.split(/\s(?=(?:[^'}]|'[^']*'|{{[^}]*}})*$)/)
.map(&:strip)
.reject(&:empty?)
end
def render(context)
# First file is the target zip archive path
target, files = resolve_parameters(context)
abort 'zip tag must be called with at least two files' if files.empty?
zipfile_path = CACHE_FOLDER + target
FileUtils.makedirs(File.dirname(zipfile_path))
# Create the archive. Delete file, if it already exists
File.delete(zipfile_path) if File.exist?(zipfile_path)
Zip::File.open(zipfile_path, Zip::File::CREATE) do |zipfile|
files.each do |file|
# Two arguments:
# - The name of the file as it will appear in the archive
# - The original file, including the path to find it
zipfile.add(File.basename(file), file)
end
end
puts "Created archive #{zipfile_path}"
# Add the archive to the site's static files
site = context.registers[:site]
site.static_files << Jekyll::StaticFile.new(site, "#{site.source}/#{CACHE_FOLDER}",
File.dirname(target),
File.basename(zipfile_path))
# No rendered output
''
end
def resolve_parameters(context)
# Resolve the given parameters to a file list
target, files = @files.map do |file|
next file unless file.match(VARIABLE_SYNTAX)
# This is a variable. Look it up.
context[file]
end
[target, files]
end
end
end
Liquid::Template.register_tag('zip', Jekyll::ZipBundlerTag)
我的 Jekyll 页面旨在为编码书籍的练习提供示例解决方案。 解决方案是一堆 .cpp 文件(C++ 代码文件)存储在我的 Jekyll 项目中的一个文件夹中,这样我就可以在 IDE.
中打开同一个文件夹我已经设法为每本书的章节自动生成一页,将相关解决方案显示为代码块列表(每个练习一个)。我通过遍历 site.static_files
并通过文件名中的数字识别文件来做到这一点(例如,第 1 章的两个解决方案:01_1_FirstSolution.cpp
、01_2_SecondSolution.cpp
)
现在,我还想为每本书的章节提供一个 zip 存档,其中包含相关的 .cpp 文件。我不想手动制作 zip 文件,因为那样我将无法再简单地更改其中一个代码文件。理想情况下,我想在循环 site.static_files
并过滤相关文件的同时构建一个 zip 文件。
我搜索这个的时候,主要是找到了一些速度优化插件,用于打包和压缩资源。我是 运行 Jekyll Windows。
Jekyll 主要是静态网站构建器,因此在使用 Jekyll 构建之前 运行 一个程序或 shell 脚本并将它们输出到 site.static_files
可能是理想的选择您希望输出到的位置如上。
您可以在 运行ning Jekyll 之前使用脚本来压缩您的文件,然后 运行 Jekyll 构建过程。
还有 Generator plugins 您可以使用插件或 Ruby 对 运行 脚本的 system
命令来实现类似的结果你的构建。
如果可以获取文件内容(fetch etc.) you may use JSZip 库将它们打包成 Zip。我不确定这是否适合你在 jekyll 中...但我会尝试这样做。
要尝试示例,只需创建一个 html 文件或 open my example with fetch。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.6.0/jszip.min.js" integrity="sha512-uVSVjE7zYsGz4ag0HEzfugJ78oHCI1KhdkivjQro8ABL/PRiEO4ROwvrolYAcZnky0Fl/baWKYilQfWvESliRA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script type="module" src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.0/FileSaver.min.js" integrity="sha512-csNcFYJniKjJxRWRV1R7fvnXrycHP6qDR21mgz1ZP55xY5d+aHLfo9/FcGDQLfn2IfngbAHd8LdfsagcCqgTcQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head>
<body>
<script>
var zip = new JSZip();
zip.file("Hello.txt", "Hello World\n");
zip.file("Hello2.txt", "Hello2 World\n");
//var img = zip.folder("images");
//img.file("smile.gif", imgData, {base64: true});
zip.generateAsync({type:"blob"})
.then((content) => {
// see FileSaver.js
saveAs(content, "example.zip");
});
</script>
</body>
</html>
有 jekyll-zip-bundler 插件。
如何使用
作为多个参数的文件名:
{% zip archiveToCreate.zip file1.txt file2.txt %}
文件名中的空格:
{% zip archiveToCreate.zip file1.txt folder/file2.txt 'file with spaces.txt' %}
包含文件列表的变量也是可能的:
{% zip ziparchiveToCreate.zip {{ chapter_code_files }} %}
插件代码
# frozen_string_literal: true
# Copyright 2021 by Philipp Hasper
# MIT License
# https://github.com/PhilLab/jekyll-zip-bundler
require 'jekyll'
require 'zip'
# ~ gem 'rubyzip', '~>2.3.0'
module Jekyll
# Valid syntax:
# {% zip archiveToCreate.zip file1.txt file2.txt %}
# {% zip archiveToCreate.zip file1.txt folder/file2.txt 'file with spaces.txt' %}
# {% zip {{ variableName }} file1.txt 'folder/file with spaces.txt' {{ otherVariableName }} %}
# {% zip {{ variableName }} {{ VariableContainingAList }} %}
class ZipBundlerTag < Liquid::Tag
VARIABLE_SYNTAX = /[^{]*(\{\{\s*[\w\-.]+\s*(\|.*)?\}\}[^\s{}]*)/mx.freeze
CACHE_FOLDER = '.jekyll-cache/zip_bundler/'
def initialize(tag_name, markup, tokens)
super
# Split by spaces but only if the text following contains an even number of '
# Based on
# Extended to also not split between the curly brackets of Liquid
# In addition, make sure the strings are stripped and not empty
@files = markup.strip.split(/\s(?=(?:[^'}]|'[^']*'|{{[^}]*}})*$)/)
.map(&:strip)
.reject(&:empty?)
end
def render(context)
# First file is the target zip archive path
target, files = resolve_parameters(context)
abort 'zip tag must be called with at least two files' if files.empty?
zipfile_path = CACHE_FOLDER + target
FileUtils.makedirs(File.dirname(zipfile_path))
# Create the archive. Delete file, if it already exists
File.delete(zipfile_path) if File.exist?(zipfile_path)
Zip::File.open(zipfile_path, Zip::File::CREATE) do |zipfile|
files.each do |file|
# Two arguments:
# - The name of the file as it will appear in the archive
# - The original file, including the path to find it
zipfile.add(File.basename(file), file)
end
end
puts "Created archive #{zipfile_path}"
# Add the archive to the site's static files
site = context.registers[:site]
site.static_files << Jekyll::StaticFile.new(site, "#{site.source}/#{CACHE_FOLDER}",
File.dirname(target),
File.basename(zipfile_path))
# No rendered output
''
end
def resolve_parameters(context)
# Resolve the given parameters to a file list
target, files = @files.map do |file|
next file unless file.match(VARIABLE_SYNTAX)
# This is a variable. Look it up.
context[file]
end
[target, files]
end
end
end
Liquid::Template.register_tag('zip', Jekyll::ZipBundlerTag)