Abstract syntax tree Abstract syntax tree Abstract syntax tree Abstract syntax tree
Background: When we introduce two methods in a package at the same time, there are two forms
The first form
import {flatten,join} from 'lodash';
Copy the code
Second form
import flatten from 'lodash/flatten';
import join from 'lodash/join';
Copy the code
Comparing the two forms, we can see:
The introduction of the first method introduces the entire Lodash package and the second method guides two methods into the entire package
Obviously we’re going to use the second one
However, most projects are in the form of import deconstruction, so we will write a plug-in here, and when we write the first form, we will use the plug-in to convert it into the second form
This is the function of the plug-in we are going to write
Step 1: Initialize a Webpack project
npm i webpack webpack-cli babel-core babel-loader babel-preset-env babel-preset-stage-0 -D
Copy the code
In Webpack, the mode variable is provided to configure the runtime environment, and the value of mode can be development, which stands for development mode, or production, which stands for production mode.
Write the compiled command in package.json
"scripts": {"build":"webpack --mode production/development"
}
Copy the code
Step 2: Create a project structure
Webpack-plugin // project name dist // Bundle output directory bundle.js // package output file SRC // main logic index.js // project entry file./ /babelrc // syntax parsing configuration package.json webpack.config.jsCopy the code
Step 3: Write the webPack configuration file
const path = require('path');
module.exports = {
entry: './src/index.js'// output: {path: path.join(__dirname,'dist'), // output path filename:'bundle.js'// configure module: {// configure loader rules: [{test: /\.js$/,
loader: 'babel-loader'}}}]Copy the code
Step 4: Configure.babelrc
{
"presets": [
"env"."stage-0"]."plugins": [[/ /"demand-loading"// This is a plugin name that we wrote ourselves."library": "lodash"// Which library do we use when we reference lodash library},"syntax-decorators"]]}Copy the code
Step 5: Write the comparison script in index.js
// import {flatten,join} from 'lodash'
import flatten from 'lodash/flatten'
import join from 'lodash/join'
Copy the code
Let’s introduce the last two sentences and wrap them up
Hash: fCB0bd5D9734b5f56676 Version: webPack 4.2.0 Time: 346ms Built at: [emitted by means of Entrypoint main = bundle.js] Asset Size Chunks bundle.js [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 823 bytes {main} [built] [./src/index.js] 286 bytes {main} [built] + 15 hidden modulesCopy the code
Looking at the packaged code in this way, we see that this way into the packaged size is. 21.3 k.
Then comment out the next two lines and introduce only the first line
Hash: aa8b689e1072463fc1cd
Version: webpack 4.2.0
Time: 3277ms
Built at: 2018-3-27 21:30:22
Asset Size Chunks Chunk Names
bundle.js 483 KiB main [emitted] main
Entrypoint main = bundle.js
[./node_modules/webpack/buildin/amd-options.js] (webpack)/buildin/amd-options.js 82 bytes {main} [built]
[./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 823 bytes {main} [built]
[./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 521 bytes {main} [built]
[./src/index.js] 47 bytes {main} [built]
+ 1 hidden module
Copy the code
The size of the package is 483K
The comparison proves the difference between the two methods of introduction
Step 6: Let’s write the plugin!
Let’s start by comparing the abstract syntax trees of the two introductions
By comparison, we find that the ImportDeclaration is different
const babel = require('babel-core');
const types = require('babel-types');
letVisitor = {// Where ref is the second parameter to ImportDeclaration, where the value is {// in.babelrc"library": "lodash"ImportDeclaration(path, ref={options:{}}) {ImportDeclaration(path, ref={options:{}}) {let node = path.node;
let specifiers = node.secifiers
if(options.library == node.soure.value && ! types.isImportDeclaration(specifiers[0])) {let newImport = specifiers.map((specifier) => (
types.importDeclaration([types.ImportDefaultSpecifier(specifier.local)], types.stringLiteral(`${node.soure.value}/${specifier.local.name}`)))); path.replaceWithMultiple(newImport) } } } const code ="import {flatten, join} from 'lodash';";
let r = babel.transform(code, {
plugins: [
{visitor}
]
})
Copy the code
When creating the replacement logic, the methods on Types use this url on Github, which doesn’t search for which, mom doesn’t have to worry about my learning anymore. Hee hee
Step 7: Tidy up the above code and put it in node_modules
Create a new folder named “babel-plugin-demand-loading” and place it in node_modules. Create a new file named “index.js” and put the following code init. Then go to this folder and initialize a package.json file. The entry file inside is called index.js
Matters needing attention:
The Babel plugin must be named babel-plugin-xxx(the name of the plugin you wrote), otherwise it will not be successful. The Babel plugin returns an object with a visitor object that holds our conversion code
const babel = require('babel-core');
const types = require('babel-types'); Module.exports = {visitor: {// where ref is the second parameter of ImportDeclaration, where the value is {// in. Babelrc"library": "lodash"ImportDeclaration(path, ref={}) {ImportDeclaration(path, ref={}) {let { opts } = ref
let node = path.node;
let specifiers = node.specifiers
if(opts.library == node.source.value && ! types.isImportDeclaration(specifiers[0])) {let newImport = specifiers.map((specifier) => (
types.importDeclaration([types.ImportDefaultSpecifier(specifier.local)], types.stringLiteral(`${node.source.value}/${specifier.local.name}`)))); path.replaceWithMultiple(newImport) } } } }Copy the code
Finally, after NPM run build is compiled, it is found that the packaged size is. 20k plus means our plugin works.
Do you know how to do it by now? Hee hee!
Don’t be bored with the familiar, make a little progress every day; Don’t be afraid of new things. Learn a little every day.