Use webpack program to build small projects

This article is reproduced in: Ape 2048 Website ➥ https://www.mk2048.com/blog/blog.php?id=hkc0chhjaa

In this article

  • Webpack how to develop plug-ins and development of small packaged plug-ins
  • Problems encountered in the development process and how to solve
  • What mini-program-webpack-loader can do

Development webpack plug

I believe the students worked on plug-ins, have seen Writing a Plugin or similar article, because just webpack the development of mini-program-webpack-loader 4 released this tool, so I read the article, by the way read the following few documents.

If you read the document, I believe you must know:

  • Each plug-in must be apply methods for webpack engine executes the code you want to execute.
  • Two important objects and Compiler Compilation, you can bind an event hook (webpack to perform this procedure when calling) above, which specific event hook can read Compiler Hooks .
  • The relationship between the module and the chunk, we can understand each file will have a module, and a chunk is composed of a plurality of module to.
  • webpack entire package process those events
  • How to write a simple loader

If you feel unable to proceed, may I continue to see step by step how to develop and improve the mini-program-webpack-loader to pack applet.

Applets have a fixed routine, you first need to have a app.json file for all pages path and each page has four files: .js, .json, .wxml, .wxss. So I order app.json as webpack entry, when webpack execution apply plug-in, to get to know by what are entry applet page. Probably something like a flow chart, a small plug-packaged almost so complete.

This uses two plug-in MultiEntryPlugin, SingleEntryPlugin. Why do it? Because the number of webpack be configured (entry here is not just webpack configuration in the entry, import (), require.ensure () will generate an entry) based on your entry to determine the generated files, we do not want to put all the pages js packaged into a file, you need to use SingleEntryPlugin to generate a new entry module; and those static resources, we can use MultiEntryPlugin plug-in to process these documents as an entry module dependencies, configuration to the static file-loader in the loader file output. Pseudo-code as follows:

 const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin');
 const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
 
 class MiniPlugin {
    apply (compiler) {
        let options = compiler.options
        let context = compiler.rootContext
        let entry = options.entry
        let files = loadFiles(entry)
        let scripts = files.filter(file => /\.js$/.test(file))
        let assets = files.filter(file => !/\.js$/.test(file))
        
       new  MultiEntryPlugin(context, assets, '__assets__').apply(compiler)
        
        scripts.forEach((file => {
            let fileName = relative(context, file).replace(extname(file), '');
            new SingleEntryPlugin(context, file, fileName).apply(compiler);
        })
    }
 }

Of course, if you do that like the above, you will find that the final will be more of a main.js, xxx.js (fill in when using MultiEntryPlugin name), main.js corresponding configuration entry is generated files, xxx.js is MultiEntryPlugin generated. These files are not what we need, so it is necessary to remove him. If you are familiar webpack document, we have a lot of places you can modify the package out of the final document, such as the compiler emit events, compilation of related events optimizeChunks can be achieved. Its essence is to modify compilation.assets object.

In the mini-program-webpack-loader on the use of the event to handle content emit such unwanted output. Probably the process like this:

Small packaged course not so simple, had to support wxml, wxss, wxs and self-referential definition of the components, so this time we need to complete a loader, loader needs to be done is very simple - to resolve dependent files, such as .wxml need to resolve src import components, wxs of src, .wxss need to parse @ import, wxs's require, and finally add the method can be used loadModule in the loader. Custom assembly of a direct access start when the add entry step, it is not necessary to complete the loader. This time the map:

It would also be no problem, but development experience is relatively poor, such as add a custom component, a page, webpack is not aware of, so it is necessary to check when .json changes in the page is not new custom components or add a page. This time encounter a problem, since js custom component is not by addModule way to add, because the self-js-defined components must file a separate entrance. It does not in the loader, so try the files to the plugin (because plugin loader prior to execution, it is possible to establish plugin loader and communication). Simple and crude way:

// loader.js
class MiniLoader {}

module.exports = function (content) {
    new MiniLoader(this, content)
}
module.exports.$applyPluginInstance = function (plugin) {
  MiniLoader.prototype.$plugin = plugin
}

// plugin.js
const loader = require('./loader')
class MiniPlugin {
    apply (compiler) {
        loader.$applyPluginInstance(this);
    }
}

but.... Plugin file is reached, and then use SingleEntryPlugin but when you will find no effect. Because after the compiler make webpack not aware of the new module has been added, it is of no use, when you need to guess based on this document, how to get webpack perceived the new module, do keyword search according to document events, can be found when compiling the finished compilation needAdditionalPass event will call hook:

    this.emitAssets(compilation, err => {
    	if (err) return finalCallback(err);
    
    	if (compilation.hooks.needAdditionalPass.call()) {
    		compilation.needAdditionalPass = true;
    
    		const stats = new Stats(compilation);
    		stats.startTime = startTime;
    		stats.endTime = Date.now();
    		this.hooks.done.callAsync(stats, err => {
    			if (err) return finalCallback(err);
    
    			this.hooks.additionalPass.callAsync(err => {
    				if (err) return finalCallback(err);
    				this.compile(onCompiled);
    			});
    		});
    		return;
    	}
    
    	this.emitRecords(err => {
    		if (err) return finalCallback(err);
    
    		const stats = new Stats(compilation);
    		stats.startTime = startTime;
    		stats.endTime = Date.now();
    		this.hooks.done.callAsync(stats, err => {
    			if (err) return finalCallback(err);
    			return finalCallback(null, stats);
    		});
    	});
    });

If you return a true value in the event the hook, you can call the compiler additionalPass webpack event hook, try to add a file here, it really is possible. This time the map has become this:

Of course, small packaged some different places, such as subcontracting, how to make good splitchunk, not winded in LA, when you start later you will find that there are many ways to achieve the desired effect.

Plug-in Development here almost, in general, webpack is changing the pattern of the correction, when you know what to do when each callback, webpack with them much easier. Obviously I do not know, because some of the problems encountered in the development process.

Problems encountered

1. How to support resolve alias, node_modules applet code?

Since it is a tool, of course, need to do more things, there is a small program like this so complicated, if supported resolve alias, node_modules project can make it easier to maintain, and perhaps you will say that this is not webpack most basic functions do not we of course, is hoping to use the alias in any document, node_modules support more than just js. Of course, this means that things will become complicated, first of all is to get the file path, it must be asynchronous because webpack resolve 4 is no longer supported in sync. The second is the name of the directory applet can not be node_modules, then we need a rule to calculate the relative path, or a relative packaging output, rather than relative to the current project directory.

2. Merge multiple small projects program

There praise from childhood program is concerned, there are micro-mall version, retail version and the public version, most basic function, the business is the same, of course, can not develop once for each applet, so this tool with merge multiple small of course, the program is a must. Such a merger than a little and take the file from node_modules complex, because of the need to ensure that the number of small programs merge the page is correct, but also to ensure the same path.

The final solution to these two problems both to the src directory webpack rootContext directory as a reference to calculate the absolute path of the directory where the package file path, and then calculate a final output path according to the path of the directory where the file app.json entrance.


exports.getDistPath = (compilerContext, entryContexts) => {
  /**
   * webpack 以 config 所在目录的 src 为打包入口
   * 所以可以根据该目录追溯源文件地址
   */
  return (path) => {
    let fullPath = compilerContext
    let npmReg = /node_modules/g
    let pDirReg = /^[_|\.\.]\//g

    if (isAbsolute(path)) {
      fullPath = path
    } else {
      // 相对路径:webpack 最后生成的路径,打包入口外的文件都以 '_' 表示上级目录

      while (pDirReg.test(path)) {
        path = path.substr(pDirReg.lastIndex)
        fullPath = join(fullPath, '../')
      }

      if (fullPath !== compilerContext) {
        fullPath = join(fullPath, path)
      }
    }
    // 根据 entry 中定义的 json 文件目录获取打包后所在目录,如果不能获取就返回原路径
    let contextReg = new RegExp(entryContexts.join('|'), 'g')

    if (fullPath !== compilerContext && contextReg.exec(fullPath)) {
      path = fullPath.substr(contextReg.lastIndex + 1)
      console.assert(!npmReg.test(path), `文件${path}路径错误:不应该还包含 node_modules`)
    }

    /**
     * 如果有 node_modules 字符串,则去模块名称
     * 如果 app.json 在 node_modules 中,那 path 不应该包含 node_modules 
     */

    if (npmReg.test(path)) {
      path = path.substr(npmReg.lastIndex + 1)
    }

    return path
  }
}

3. How to handle the package into separate packaged content dependent sub-encapsulated

The solution to this problem is through optimizeChunks event, add this chunk of entry file in the dependency of each chunk of the module, and then check the number of module is dependent on test configuration splitChunk in. If only one, and is dependent on the quilt package, the package into sub-packages.

4.webpack support single file failed

This is not a problem when trying to use webpack to support a single file, it seems not so easy:

  • Split a single file after file into four files, you can use emitFile and addDependency to create the file, but does not execute loader created
  • Use loadModule because of file system the file does not exist will complain

Written in the last

Finally, of course, is what describes the mini-program-webpack-loader can do.

The tool is primarily address the following issues:

  • Applets are not supported npm
  • Directory nesting too deep, difficult path management
  • Old project is too big, too costly want to use the new tools
  • A large small items to conventional optimization tips

Repeat

  • You can directly use npm to download zanui-weapp the
  • You can say goodbye to "../../../../../xxx" the
  • You can use mpVue, taro to write new features, do not worry incompatible

Finally, the last to leave the document addresses: Mini-Program-WebPACK-Loader

Guess you like

Origin www.cnblogs.com/htmlandcss/p/11785237.html