Skip to content

模块化&webpack

大纲

  1. 模块化
  2. webpack

模块化

  1. 全局 function模式
js
   function m1(){}
   function m2(){}
  1. namespace 模式
js
let myModule = {
    data:"test",
    foo(){

    }
}
  1. IIFE 模式 匿名函数自调用
js
    (function(window){
        let data = "test";
        function test(){

        }
        windos.module = {
            data,test
        }
        // TODO jQuery
    })(window)
  1. IIFE 模式增强 引入依赖
js
    (function(window,$){
        let data = "test";
        function test(){

        }
        windos.module = {
            data,test
        }
        // TODO jQuery
    })(window,jQuery)
  1. 模块化规范 commonjs node - 运行时 暴露模块 module.exports = {} 引入模块 require('')
  2. AMD CMD ES6 UMD ES6 - 编译时 基本使用 export import xx from xx

webpack

webpack.config.js

js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 从css文件中提取css代码到单独的文件中,对css代码进行代码压缩等
const MiniCssExtraPlugin = require('mini-css-extra-plugin');
module.exports = {
    mode:'development',
    // 单入口
    // entry: path.resolve(__dirname,'../../main.js'),
    // 如果多入口(生成多个html),要配合下面的plugins
    entry: {
        main:path.resolve(__dirname,'../../main.js'),
        header:path.resolve(__dirname,'../../header.js'),
    },
    output:{
        filename: '[name].[hash:8].js',
        path: path.join(__dirname,'../dist'),
        clean:true
    },
    module:{
        rules:[
            {
                test:/\.css$/,
                // use:['style-loader','css-loader'], //这里如果使用了MiniCssExtraPlugin就不能使用'style-loader'
                use:[MiniCssExtraPlugin.loader,'css-loader'],
            },
            {
                test:/\.less$/,
                // use:['style-loader','css-loader','less-loader'], //顺序不能错,从后往前
                use:[MiniCssExtraPlugin.loader,'css-loader','less-loader'], 
            },
            {
                test:/(\.jsx|.js)$/,
                use:['babel-loader',path.resolve(__dirname,'../loader/drop-console.js')], //此处引用的下文的drop-console.js
                exlude:/node_modules/,
            },
        ]
    },
    plugins:[
        new HtmlWebpackPlugin({
            template: path.relative(__dirname,'../publice/index,html'),
            title:'webpack0507',
            chunks:['main'],
            filename:'index.html'
        }),
        new HtmlWebpackPlugin({
            filename:'header.html',
            chunks:['header'],
        }),
        new MiniCssExtraPlugin({
            filename: '[name].[hash:8].css',
            chunkFilename:'[id].css'
        }),
    ],
}

babel

es6语言降级

@babel/core babel 核心库 babel-loader @babel/preset-env 一组预先设定的插件 默认支持所有的最新js(包括ES6 ES6+) @babel/plugin-transfom-runtime async await import 提前把垫片加载到环境中

loader

编写原则

  • 单一原则-每个loader只做一件事情
  • 链式调用 webpack会按照顺序链调用每个loader
  • 统一原则 输入或者输出都是字符串,即插即用
  1. input -> @babel/parser -> ast
  2. ast -> @babel/traverse -> new ast
  3. ast -> @babel/generate -> output

@babel/types 对节点进行分析

举例:
手写drop-console.js

js
// 去除代码中的console.log
// ast
const parser = require('@babel/parser');
const traverse = require('@babel/traverse').default;
const generator = require('@babel/generator').default;
const t = require('@babel/types')

module.exports = function (source) {
    const ast = parser.parse(source, { sourceType: 'module' });

    traverse(ast, {
        CallExpression(path) {
            if (
                t.isMemberExpression(path.node.callee) &&
                t.isIdentifier(path.node.callee.object, { name: 'console' })) {
                path.remove();
            }
        }
    })

    const output = generator(ast, {}, source);
    return output.code;
}

plugin

webpack继承tapable类:

  • tap 以同步方式触发钩子
  • tapAsync 以异步方式触发钩子
  • tabPromise 以异步方式触发钩子,返回promise

整个webpack会使用所有配置信息生成一个compiler

然后执行run

compilation 对象

实现一个MyPlugin

js
class MyPlugin(){
    constructor(){

    }
    apply(compiler){
        compiler.hook.done.tap('MyPlugin',()=>{
            console.log('编译完成')
        })

        compiler.hook.emit.top('MyPlugin',(complilation)=>{
            let assets = complilation.assets
            let content = '';
            Object.entries(assets).forEach((filename,statObj)=>{
                content += `文件名: ${filename} 文件大小: ${statObj.size()} \n`
            })
            console.log(content)
        })
    }
}

module.exports = MyPlugin;

use

js
plugins:{
    new MyPlugin(),
}

鄂ICP备2024055897号