Recently, we are making a demand similar to offline package. In our normal work, we usually complete a complete SPA and then package it and put it online. Because we had not the server resources, so now a solution is to wrap up the SPA for a zip package, and then uploaded to the CDN, others use it directly from the CDN pull and then unpack, this scheme is similar to develop a set of complete offline package process, which USES the best in the field of compressed jszip library, Among them also encountered many pits, hereby summary record.

Commonly used API

The official documentation has given a very detailed demo of various apis, but it is only a very simple demo, and the actual scenario we encountered in development is far from the actual scenario. The library is that the cow force support various types of resources uint8array, blob, arraybuffer, nodebuffer, string, etc., and the API is promise style, so it’s very comfortable to use, simply look at a few examples, can see the details document;

const zip = new JSZip();

// create a file
zip.file("hello.txt"."Hello World\n");

// create a file and a folder
zip.file("nested/hello.txt"."Hello World\n");
zip.folder("nested").file("hello.txt"."Hello World\n");

// access the file content
zip.file("hello.txt").async("string").then(function (data) {
  // data is "Hello World\n"
});

// remove a file or folder
zip.remove("nested/hello.txt");
zip.remove("nested");

// generate a zip file
var promise = null;
if (JSZip.support.uint8array) {
  promise = zip.generateAsync({type : "uint8array"});
} else {
  promise = zip.generateAsync({type : "string"}); } / /read a zip file
zip.loadAsync(content)
.then(function(zip) {
    zip.file("hello.txt").async("string"); // a promise of "Hello World\n"
});
Copy the code

Compressing resources

After the development of a project, resources will be packaged into the Dist directory, so we need to package the entire Dist folder into a ZIP package, which requires two steps:

  1. Read every file in the dist directory;
function readConst files = fs.readdirsync (dirPath); Dir(zip, dirPath) {const files = fs.readdirsync (dirPath); files.forEach(fileName => { const fillPath = dirPath +"/"+ fileName; const file = fs.statSync(fillPath); // If it is a folder, you need to recurse through the following subfilesif (file.isDirectory()) {
      const dirZip = zip.folder(fileName);
      readDir(dirZip, fillPath);
    } else{// Read each file as buffer and save it in zip. File (fileName, fs.readfilesync (fillPath)); }}); }Copy the code
  1. Generate a compressed package;
function generateZip() {
  const sourceDir = path.join(__dirname, ".. /dist");
  readDir(zip, sourceDir);
  zip.generateAsync({
    type: "nodebuffer"// Compression type:"DEFLATE", // Compression algorithm compressionOptions: {// compression level: 9}}). Then (content => {const dest = path.join(__dirName,".. /zip"); // create a new package directory fs.mkdirsync (dest, {recursive:true}); // Write the zip package to disk. The content is now a buffer fs.writefilesync ('${dest}/lewis.zip`, content); 
  });
}
Copy the code

Unpack the resources

When you need to use the SPA, you can directly pull the ZIP package from THE CDN and decompress it. The decompression package is also divided into two steps:

  1. Get the ZIP file from the CDN and unzip it;
function getZipFiles(zipUrl) {
  const response = await axios({
    method: 'get',
    url: zipUrl,
    responseType: 'arraybuffer'// Type must be arraybuffer}); Const zipData = await jszip.loadAsync (response.data); const zipData = await jszip.loadAsync (response.data);return zipData.files;
}
Copy the code
  1. Write the decompressed resources into the hard disk;
functionSaveZipFiles (savePath) {const files = await getZipFiles(zipUrl) try {const files = await getZipFiles(zipUrl) try {for(const filename of Object.keys(files)) { const dest = path.join(__dirname, savePath, filename); If the file is a directory, create a folder firstif(files[filename].dir && ! isDirSync(dest)) { fs.mkdirSync(dest, { recursive:true
        });
      } else{// Write each buffer to the hard disk files[filename].async('nodebuffer')
          .then(content => fs.writeFileSync(dest, content));
      }
    }
  } catch (error) {
    console.error('save zip files encountered error! ', error.message);
    returnerror; }}Copy the code

Pay attention to

It is recommended to use buffer directly in the whole process of processing ZIP packages, and try to avoid using string. It is easy to cause garbled characters when going around. Besides, the size of buffer is small and easy to store, and jSZIP can handle it seamlessly. Fs.readfilesync () returns a string. If you add an argument to a zip file, it will return a string.

* @param file * @returns string */function getFileContent(file) {
  if (fs.existsSync(file)) {
    const pkg = fs.readFileSync(file, 'utf-8')
    return pkg
  } else {
    returnNull}} /** * Retrieving file contents * @param file * @returns buffer */function getFileBuffer(file) {
  if (fs.existsSync(file)) {
    const pkg = fs.readFileSync(file)
    return pkg
  } else {
    return null
  }
}
Copy the code

Afterword.

This requirement seems very simple, actually really developed in different scenarios or some pit, especially pay attention to the use of buffer problem when the node development, avoid some unnecessary string, speaking, reading and writing, as well as the use of some of the node synchronization API, while today rest copy down the little demand, after sharing to all the people in need!

More exciting content welcome to follow my official account [God helps Those who help Themselves Lewis]