真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

node如何鏈接多個(gè)JS模塊

本文小編為大家詳細(xì)介紹“node如何鏈接多個(gè)JS模塊”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“node如何鏈接多個(gè)JS模塊”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

創(chuàng)新互聯(lián)建站:成立于2013年為各行業(yè)開(kāi)拓出企業(yè)自己的“網(wǎng)站建設(shè)”服務(wù),為上千多家公司企業(yè)提供了專(zhuān)業(yè)的成都網(wǎng)站設(shè)計(jì)、做網(wǎng)站、成都外貿(mào)網(wǎng)站建設(shè)公司、網(wǎng)頁(yè)設(shè)計(jì)和網(wǎng)站推廣服務(wù), 按需網(wǎng)站建設(shè)由設(shè)計(jì)師親自精心設(shè)計(jì),設(shè)計(jì)的效果完全按照客戶(hù)的要求,并適當(dāng)?shù)奶岢龊侠淼慕ㄗh,擁有的視覺(jué)效果,策劃師分析客戶(hù)的同行競(jìng)爭(zhēng)對(duì)手,根據(jù)客戶(hù)的實(shí)際情況給出合理的網(wǎng)站構(gòu)架,制作客戶(hù)同行業(yè)具有領(lǐng)先地位的。

一、個(gè)人理解

瀏覽器本身只能做一些展示及用戶(hù)交互的功能,對(duì)于系統(tǒng)操作的能力很有限,那么,瀏覽器內(nèi)置的運(yùn)行環(huán)境顯然不滿(mǎn)足一些更為人性化的開(kāi)發(fā)模式,比如:更好的區(qū)分功能模塊、實(shí)現(xiàn)文件的操作。那么,帶來(lái)的缺陷就很明顯,比如:各個(gè) JS文件比較分散,需要在 html頁(yè)面里面單獨(dú)引入,如果某個(gè) JS文件需要其他的 JS庫(kù),那么很可能會(huì)因?yàn)?html頁(yè)面未引入而報(bào)錯(cuò),在功能龐大的項(xiàng)目里,手動(dòng)的管理這些功能文件確實(shí)讓人有點(diǎn)捉襟見(jiàn)肘。

那么, node到底是怎么更友好的提供開(kāi)發(fā)的呢?其實(shí),上面也說(shuō)了,人為的管理文件依賴(lài)不但會(huì)消耗大量的精力,還會(huì)存在疏漏,那么,是不是以用自動(dòng)化的方式進(jìn)行管理就會(huì)好很多?是的,在 node的運(yùn)行環(huán)境里拓寬了對(duì)系統(tǒng)的操作能力,也就是說(shuō),或許以前開(kāi)發(fā)者也想通過(guò)一些代碼來(lái)完成那些機(jī)械瑣碎的工作,但是,只有想法沒(méi)有操作權(quán)限,最后只能望洋興嘆?,F(xiàn)在,可以以 node的一些擴(kuò)展功能對(duì)文件進(jìn)行先前加工與整理,再添加一些自動(dòng)化的代碼,最后轉(zhuǎn)換為一個(gè)瀏覽器可識(shí)別的、完整的 JS文件,這樣一來(lái),多個(gè)文件的內(nèi)容,便可以匯集到一個(gè)文件。

二、創(chuàng)建文件

先創(chuàng)建一些 JS文件,如下圖所示:

node如何鏈接多個(gè)JS模塊

這些文件都是手動(dòng)創(chuàng)建,babel-core這個(gè)文件是從全局的 node_modules里面復(fù)制出來(lái)的,如下圖所示:

node如何鏈接多個(gè)JS模塊

為什么要復(fù)制出來(lái)呢?這是因?yàn)?,任何腳手架干的事其實(shí)都是為了快速搭建,但是,怎么能理解它干的什么事呢?那干脆就直接復(fù)制吧,本身,node除了一些內(nèi)置的模塊,其他的都需要通過(guò)指明 require路徑的方式來(lái)找到相關(guān)模塊,如下圖所示:

node如何鏈接多個(gè)JS模塊

通過(guò) require('./babel-core')方法,解析一個(gè)功能模塊下的方法。

1、編寫(xiě)入口文件,轉(zhuǎn)換ES6代碼

entrance.js作為入口文件,作用就是設(shè)定工作從哪開(kāi)始?怎么開(kāi)始?那么,這里的工作指的就是轉(zhuǎn)換ES6代碼,以提供瀏覽器使用。

//文件管理模塊
const fs = require('fs');
//解析文件為AST模塊
const babylon = require('babylon');
//AST轉(zhuǎn)換模塊
const { transformFromAst } = require('./babel-core');
//獲取JS文件內(nèi)容
let content = fs.readFileSync('./person.js','utf-8')
//轉(zhuǎn)換為AST結(jié)構(gòu),設(shè)定解析的文件為 module 類(lèi)型
let ast = babylon.parse(content,{
    sourceType:'module'
})
//將ES6轉(zhuǎn)換為ES5瀏覽器可識(shí)別代碼
le t { code } = transformFromAst(ast, null, {
    presets: ['es2015']
});
//輸出內(nèi)容
console.log('code:\n' + `${code}`)

上面的代碼很簡(jiǎn)單,最終的目的就是將 module類(lèi)型的 person.js文件轉(zhuǎn)換為 ES5。

let person = {name:'wsl'}
export default person

終端運(yùn)行入口文件,如下所示:

node entrance.js

打印一下代碼,如下圖所示:

"use strict";
//聲明了一個(gè) __esModule 為 true 的屬性
Object.defineProperty(exports, "__esModule", {
  value: true
});
var person = { name: 'wsl' };
exports.default = person;

可以,看到打印的代碼,里面都是瀏覽器能識(shí)別的代碼,按照常理,看看能不能直接運(yùn)行一下?

下面將這段代碼通過(guò) fs功能寫(xiě)入一個(gè) js文件并讓一個(gè)頁(yè)面引用,來(lái)看看效果:

fs.mkdir('cache',(err)=>{
    if(!err){
        fs.writeFile('cache/main.js',code,(err)=>{
            if(!err){
                console.log('文件創(chuàng)建完成')
            }
        })
    }
})

再次運(yùn)行命令,如圖所示:

node如何鏈接多個(gè)JS模塊

瀏覽器運(yùn)行結(jié)構(gòu),如圖所示:

node如何鏈接多個(gè)JS模塊

其實(shí)代碼生成完就有很明顯的錯(cuò)誤,未聲明變量,怎么會(huì)不報(bào)錯(cuò)呢?這時(shí)候,在入口文件輸入之前就需要添加一些自定義輔助代碼,來(lái)解決一下這個(gè)報(bào)錯(cuò)。

解決的方式也很簡(jiǎn)單,將原 code的未聲明的 exports變量通過(guò)自執(zhí)行函數(shù)的方式包裹一下,再返回給指定對(duì)象。

//完善不嚴(yán)謹(jǐn)?shù)腸ode代碼
function perfectCode(code){
    let exportsCode = `
    var exports = (function(exports){
    ${code}
    return exports
    })({})
    console.log(exports.default)`
    return exportsCode
}
//重新定義code
code = perfectCode(code)

看一下輸出完善后的 main.js文件

var exports = (function(exports){
    "use strict";
    Object.defineProperty(exports, "__esModule", {
    value: true
    });
    var person = { name: 'wsl' };
    exports.default = person;
    return exports
})({})
console.log(exports.default)

瀏覽器運(yùn)行,如圖所示:

node如何鏈接多個(gè)JS模塊

現(xiàn)在瀏覽器運(yùn)行正常了。

2、處理 import 邏輯

既然是模塊,肯定會(huì)存在一個(gè)模塊依賴(lài)另一個(gè)或其他很多個(gè)模塊的情況。這里先不著急,先看看person模塊引入單一 animal模塊后的代碼是怎樣的?

animal模塊很簡(jiǎn)單,僅僅是一個(gè)對(duì)象導(dǎo)出

let animal = {name:'dog'}
export default animal

person模塊引入

import animal from './animal'
let person = {name:'wsl',pet:animal}
export default person

看下轉(zhuǎn)換后的代碼

"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
var _animal = require("./animal");
var _animal2 = _interopRequireDefault(_animal);
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : { default: obj };
}
var person = { name: 'wsl', pet: _animal2.default };
exports.default = person;

可以看到,轉(zhuǎn)換后會(huì)多一個(gè)未聲明的 require方法,內(nèi)部聲明的 _interopRequireDefault方法已聲明,是對(duì) animal導(dǎo)出部分進(jìn)行了一個(gè)包裹,讓其后續(xù)的代碼取值 default的時(shí)候保證其屬性存在!

下面就需要對(duì) require方法進(jìn)行相關(guān)的處理,讓其轉(zhuǎn)為返回一個(gè)可識(shí)別、可解析、完整的對(duì)象。

是不是可以將之前的邏輯對(duì) animal模塊重新執(zhí)行一遍獲取到 animal的代碼轉(zhuǎn)換后的對(duì)象就行了?

但是,這里先要解決一個(gè)問(wèn)題,就是對(duì)于 animal模塊的路徑需要提前獲取并進(jìn)行代碼轉(zhuǎn)換,這時(shí)候給予可以利用 babel-traverse工具對(duì) AST進(jìn)行處理。

說(shuō)到這里,先看一下 JS轉(zhuǎn)換為 AST是什么內(nèi)容?

這里簡(jiǎn)單放一張截圖,其實(shí)是一個(gè) JSON對(duì)象,存儲(chǔ)著相關(guān)的代碼信息,有代碼位置的、指令內(nèi)容的、變量的等等。

node如何鏈接多個(gè)JS模塊

拿到它的目的其實(shí)就是找到import對(duì)應(yīng)節(jié)點(diǎn)下的引入其他模塊的路徑

node如何鏈接多個(gè)JS模塊

通過(guò) babel-traverse找到 AST里面 import對(duì)應(yīng)的信息

const traverse = require('babel-traverse').default;
//遍歷找到 import 節(jié)點(diǎn)
traverse(ast,{
    ImportDeclaration:({ node })=>{
        console.log(node)
    }
})

輸出看下節(jié)點(diǎn)打印的結(jié)構(gòu)

Node {
  type: 'ImportDeclaration',
  start: 0,
  end: 29,
  loc: SourceLocation {
    start: Position { line: 1, column: 0 },
    end: Position { line: 1, column: 29 }
  },
  specifiers: [
    Node {
      type: 'ImportDefaultSpecifier',
      start: 7,
      end: 13,
      loc: [SourceLocation],
      local: [Node]
    }
  ],
  source: Node {
    type: 'StringLiteral',
    start: 19,
    end: 29,
    loc: SourceLocation { start: [Position], end: [Position] },
    extra: { rawValue: './animal', raw: "'./animal'" },
    value: './animal'
  }
}

可以看到 node.source.value就是 animal模塊的路徑,需要的就是它。

擴(kuò)展入口文件功能,解析 import下的 JS模塊,

添加 require方法

//完善代碼
function perfectCode(code){
    let exportsCode = `
        //添加require方法
        let require = function(path){
            return {}
        }

        let exports = (function(exports,require){
            ${code}
            return exports
        })({},require)
    `
    return exportsCode
}

這樣轉(zhuǎn)換完的 main.js給不會(huì)報(bào)錯(cuò)了,但是,這里需要解決怎么讓 require方法返回 animal對(duì)象

let require = function(path){
    return {}
}

let exports = (function(exports,require){
    "use strict";
    Object.defineProperty(exports, "__esModule", {
        value: true
    });

    var _animal = require("./animal");
    var _animal2 = _interopRequireDefault(_animal);
    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
    var person = { name: 'wsl', pet: _animal2.default };
    exports.default = person;
    return exports
})({},require)

下面就需要添加 require方法進(jìn)行 animal對(duì)象的返回邏輯

//引入模塊路徑
let importFilesPaths = []
//引入路徑下的模塊代碼
let importFilesCodes = {}

//獲取import節(jié)點(diǎn),保存模塊路徑
traverse(ast,{
    ImportDeclaration:({ node })=>{
        importFilesPaths.push(node.source.value)
    }
})

//解析import邏輯
function perfectImport(){
    //遍歷解析import里面對(duì)應(yīng)路徑下的模塊代碼
    importFilesPaths.forEach((path)=>{
        let content = fs.readFileSync(path + '.js','utf-8')
        let ast = babylon.parse(content,{
            sourceType:'module'
        })
        let { code } = transformFromAst(ast, null, {
            presets: ['es2015']
        });
        //轉(zhuǎn)換code
        code = perfectImportCode(code)
        importFilesCodes[path] = code
    })
}

//完善import代碼
function perfectImportCode(code){
    let exportsCode = `(
        function(){
                let require = function(path){
                    let exports = (function(){ return eval(${JSON.stringify(importFilesCodes)}[path])})()
                    return exports
                }
                return (function(exports,require){${code}
                    return exports
                })({},require)
            }
        )()
    `
    return exportsCode
}

//完善最終輸出代碼
function perfectCode(code){
    let exportsCode = `
        let require = function(path){
            let exports = (function(){ return eval(${JSON.stringify(importFilesCodes)}[path])})()
            return exports
        }
        let exports = (function(exports,require){
            ${code}
            return exports
        })({},require)
        console.log(exports.default)
    `
    return exportsCode
}

上面的代碼其實(shí)沒(méi)有什么特別難理解的部分,里面的自執(zhí)行閉包看著亂,最終的目的也很清晰,就是找到對(duì)應(yīng)模塊下的文件 code代碼進(jìn)行自運(yùn)行返回一個(gè)對(duì)應(yīng)的模塊對(duì)象即可。

看下轉(zhuǎn)換后的 main.js代碼

let require = function(path){
    let exports = (function(){ return eval({"./animal":"(\n function(){\n let require = function(path){\n let exports = (function(){ return eval({}[path])})()\n return exports\n }\n return (function(exports,require){\"use strict\";\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar animal = { name: 'dog' };\n\nexports.default = animal; \n return exports\n })({},require)\n }\n )()\n "}[path])})()
    return exports
}

let exports = (function(exports,require){
    "use strict";
    Object.defineProperty(exports, "__esModule", {
    value: true
    });

    var _animal = require("./animal");
    var _animal2 = _interopRequireDefault(_animal);

    function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }


    var person = { name: 'wsl', pet: _animal2.default };
    exports.default = person;
    return exports
})({},require)
console.log(exports.default)

刷新瀏覽器,打印結(jié)果如下:

node如何鏈接多個(gè)JS模塊

可以看到,pet屬性被賦予了新值。

三、完整的入口文件代碼

const fs = require('fs');
const babylon = require('babylon');
const traverse = require('babel-traverse').default;
const { transformFromAst } = require('./babel-core');
//解析person文件
let content = fs.readFileSync('./person.js','utf-8')
let ast = babylon.parse(content,{
    sourceType:'module'
})

//引入模塊路徑
let importFilesPaths = []
//引入路徑下的模塊代碼
let importFilesCodes = {}

//保存import引入節(jié)點(diǎn)
traverse(ast,{
    ImportDeclaration:({ node })=>{
        importFilesPaths.push(node.source.value)
    }
})

//person.js 對(duì)應(yīng)的code
let { code } = transformFromAst(ast, null, {
    presets: ['es2015']
});

//解析import邏輯
function perfectImport(){
    importFilesPaths.forEach((path)=>{
        let content = fs.readFileSync(path + '.js','utf-8')
        let ast = babylon.parse(content,{
            sourceType:'module'
        })
        let { code } = transformFromAst(ast, null, {
            presets: ['es2015']
        });
        code = perfectImportCode(code)
        importFilesCodes[path] = code
    })
}

//完善import代碼
function perfectImportCode(code){
let exportsCode = `
    (
    function(){
        let require = function(path){
        let exports = (function(){ return eval(${JSON.stringify(importFilesCodes)}[path])})()
            return exports
        }
        return (function(exports,require){${code}
            return exports
        })({},require)
        }
    )()
    `
    return exportsCode
}

//開(kāi)始解析import邏輯
perfectImport()

//完善最終代碼
function perfectCode(code){
    let exportsCode = `
        let require = function(path){
            let exports = (function(){ return eval(${JSON.stringify(importFilesCodes)}[path])})()
            return exports
        }
        let exports = (function(exports,require){
            ${code}
            return exports
        })({},require)
        console.log(exports.default)
    `
    return exportsCode
}

//最后的代碼
code = perfectCode(code)

//刪除文件操作
const deleteFile = (path)=>{
    if(fs.existsSync(path)){
        let files = []
        files = fs.readdirSync(path)
        files.forEach((filePath)=>{
            let currentPath = path + '/' + filePath
            if(fs.statSync(currentPath).isDirectory()){
                deleteFile(currentPath)
            } else {
                fs.unlinkSync(currentPath)
            }
        })
        fs.rmdirSync(path)
    }
}

deleteFile('cache')

//寫(xiě)入文件操作
fs.mkdir('cache',(err)=>{
        if(!err){
            fs.writeFile('cache/main.js',code,(err)=>{
            if(!err){
                console.log('文件創(chuàng)建完成')
            }
        })
    }
})

讀到這里,這篇“node如何鏈接多個(gè)JS模塊”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


文章標(biāo)題:node如何鏈接多個(gè)JS模塊
網(wǎng)站URL:http://weahome.cn/article/pdpjoc.html

其他資訊

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部