1120-commonjs原理 & requirejs原理 & webpack简易版实现

commonjs是通过module.exports导出模块,用require引入一个模块,原理闭包;

a.js

module.exports = "commonjs"
复制代码

b.js

let str = require('./a.js');
console.log(str);
复制代码

js实现req方法模拟coomonjs的模块导出引入

let fs = require(fs)
function req(moduleName){
    let content = fs.readFileSync(moduleName);
    let fn  = new Function("exports","module","require","__dirname","__filename",content+"\n return module.exports")
    let module = {
        exports:{}
    };
    return fn(module.exports,module,req,__dirname,__filename);
}
复制代码

原理:commonjs就是读取文件内容,然后创建了一个匿名函数,然后将匿名函数执行结果返回。

  function (exports,module,require,__dirname,__filename) {
     module.exports = 'commonjs';
     return moodule.exports;
  }
复制代码

requirejs是通过define定义导出模块,用require引入模块。

define('name',[],function(){
    return 'requirejs'
})
define('say',['name'].function(name){
    return `my name is ${name}`
})
require(['say'],function(text){
    console.log(text)
})
复制代码

js实现define 和require方法

let factories = {}
function define(moduleName,dependencies,factory){
    factory.dependencies = dependencies;//记住对应的依赖关系
    factories[moduleName] = factory;
}
function require(mods,callback){
    let result =  mods.map(mod=>{
        let factory = factories[mod];
        let exports ;
        let dependencies = factory.dependencies;
        require(dependencies,function(...args){//递归处理依赖关系
            exports = factory.apply(null,args)
        })
        return exports;
    })
    callback.apply(null,result)
}
复制代码

webpack简易版

webpack构建可进行代码打包、压缩,可处理es6的模块化

全局安装

npm install webpack -g   不推荐(版本号问题)
复制代码

本地安装

npm init -y
npm install webpack webpack-cli  -D (4.0+需要安装两个一个webpack 一个webpack-cli)
npm info +包名 查看包的信息(包括包的最新版本号)
复制代码

node8.0+ 自带了npx,npx可以直接执行文件

在node_modules中 .bin 目录 有webpack。
控制台直接npx webpack,就会把webpack文件执行,webpack默认以当前执行目录为基准,找到src下的index.js文件打包到dist目录;
webpack 新增了两种模式 mode ,可以指定开发环境打包  还是 生产环境打包,不指定默认是生产环境
npx webpack --mode development ,开发环境打包,不压缩。
npx webpack --mode production 生产环境,会压缩成1行。
复制代码

模拟webpack实现自己的一个简易脚手架;

查看webpack打包的结果,主要的代码,其中eval中的为js文件中的代码内容。
(function (modules) {
    function require(moduleId) {
        var module = installedModules[moduleId] = {
            exports: {}
        };
        modules[moduleId].call(module.exports, module, module.exports, require);
        return module.exports;
    }
    return require("./src/index.js");
})
({
"./src/a.js":  (function (module, exports) {eval(""}),
"./src/index.js":(function (module, exports, require) {eval("");})
});
复制代码
脚手架名称:juejinpack
作用:将src目录下的js打包到dist目录中
1.创建包juejinpack>bin>juejinpack.js
2.初始化包juejinpack => npm init -y
3.修改package.json的bin设置 为 juejinpack.js
4.npm link将juejinpack升级为全局命令
 将juejinpack软连接添加到 usr/local/bin中;
 将juejinpack包添加到全局usr/local/lib/node_modules中。
5.全局就可以使用juejinpack;会把当前执行目录的src中的js进行打包。
复制代码

juejinpack.js 描述如何打包.

let entry = './src/index.js';//入口文件(webpack是读取配置文件)
let output = './dist/main.js';//出口(webpack是读取配置文件)
let fs = require('fs');
let path = require('path');
let ejs = require('ejs');   //npm install ejs -D,ejs模版
let script = fs.readFileSync(entry,'utf8');//读取入口文件
let styleLoader = function (source) {
    //此处是自己实现一个简易的style-loader转换功能,source 代表样式文件中的内容
    return `
        let style = document.createElement('style');
        style.innerText = ${JSON.stringify(source).replace(/\\r/g,'').replace(/\\n/g,'')};
        document.head.appendChild(style)
    `
};
// 处理模块之间依赖关系
let modules = [];
script = script.replace(/require\(['"](.+?)['"]\)/g,function () {
    //  ./a.js 替换为 ./src/a.js
    let name = path.join('./src',arguments[1]);  
    //  读取依赖的文件
    let content = fs.readFileSync(name,'utf8'); 
    // ./src.index.css
    if(/\.css$/.test(name)){
        content = styleLoader(content)
    }
    // 生成modules
    modules.push({  
        name,
        content
    });
    return `require('${name}')`
});
//定义模版,就是webpack打包后的主要代码
let template2 =`
(function (modules) {

    function require(moduleId) {
        var module =  {
            exports: {}
        };

        modules[moduleId].call(module.exports, module, module.exports, require);
        module.l = true;
        return module.exports;
    }

    return require("<%-entry%>");
})
({
    "<%-entry%>":

        (function (module, exports, require) {

           eval(\`<%-script%>\`)
        })
        <%for(let i=0;i<modules.length;i++){
            let module = modules[i];%>,
        "<%-module.name%>":

        (function (module, exports, require) {

           eval(\`<%-module.content%>\`)
        })
        
        <%}%>

});`;

let result = ejs.render(template2,{entry,script,modules});// result为替换后的结果,最终写到dist目录下
fs.writeFileSync(output,result);
console.log('编译成功')
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值