Skip to main content

3 posts tagged with "node"

View All Tags

· 4 min read
本地多个包相互依赖,如何去本地npm安装并测试呢?

项目结构

npmTest
├─ .DS_Store
├─ a
│ ├─ .DS_Store
│ ├─ index.mjs
│ ├─ package-lock.json
│ └─ package.json
├─ b
│ ├─ .DS_Store
│ ├─ index.mjs
│ └─ package.json
└─ c
├─ index.mjs
└─ package.json

假设有三个package

a项目依赖b项目,b项目依赖c项目 安装的时候只在a项目下安装依赖,即npm install --save ./b

a -> package.json 如下:

  {
"name": "b",
"version": "2.0.0",
"description": "",
"main": "index.mjs",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"c": "file:../c"
}
}

a -> index.mjs 如下:

  import c from 'c';

export default c;

a -> node_modules 目录结构 如下:

node_modules
├─ b
│ ├─ node_modules
│ ├─ c
| ├─ index.mjs
| ├─ package.json

a项目node_modules里面b依赖包会与 ./b 建立软连接,方便开发在本地调试。

查看npm解析安装依赖包详细情况

npm install --verbose (打印详细信息) npm install --loglevel silly (答应更加具体的解析安装详情) npm install --loglevel silly 2>&1 | tee log.txt (输出安装依赖信息到log.txt文件中 2>&1 输出成单个流; tee 读取标准输入到数据,并将内容输出成文件)

npm info it worked if it ends with ok
npm verb cli [
npm verb cli '/usr/local/bin/node',
npm verb cli '/usr/local/bin/npm',
npm verb cli 'install',
npm verb cli '--loglevel',
npm verb cli 'silly'
npm verb cli ]
npm info using npm@6.14.15
npm info using node@v14.16.0
npm verb npm-session 85e124dc20badd09
npm sill install runPreinstallTopLevelLifecycles
npm sill preinstall a@1.0.0
npm info lifecycle a@1.0.0~preinstall: a@1.0.0
npm sill install loadCurrentTree
npm sill install readLocalPackageData
npm timing stage:loadCurrentTree Completed in 9ms
npm sill install loadIdealTree
npm sill install cloneCurrentTreeToIdealTree
npm timing stage:loadIdealTree:cloneCurrentTree Completed in 1ms
npm sill install loadShrinkwrap
npm timing stage:loadIdealTree:loadShrinkwrap Completed in 6ms
npm sill install loadAllDepsIntoIdealTree
npm timing stage:loadIdealTree:loadAllDepsIntoIdealTree Completed in 3ms
npm timing stage:loadIdealTree Completed in 11ms
npm sill currentTree a@1.0.0
npm sill currentTree └─┬ b@2.0.0
npm sill currentTree └── c@1.0.0
npm sill idealTree a@1.0.0
npm sill idealTree └─┬ b@2.0.0
npm sill idealTree └── c@1.0.0
npm sill install generateActionsToTake
npm timing stage:generateActionsToTake Completed in 2ms
npm sill diffTrees action count 0
npm sill decomposeActions action count 0
npm sill install executeActions
npm sill doSerial global-install 0
npm verb correctMkdir /Users/xf/.npm/_locks correctMkdir not in flight; initializing
npm verb lock using /Users/xf/.npm/_locks/staging-cc44cd3a0fd01acc.lock for /Users/xf/Documents/Test/test/js/npmTest/a/node_modules/.staging
npm sill doParallel extract 0
npm sill doReverseSerial unbuild 0
npm sill doSerial remove 0
npm sill doSerial move 0
npm sill doSerial finalize 0
npm sill doParallel refresh-package-json 0
npm sill doParallel preinstall 0
npm sill doSerial build 0
npm sill doSerial global-link 0
npm sill doParallel update-linked 0
npm sill doSerial install 0
npm sill doSerial postinstall 0
npm verb unlock done using /Users/xf/.npm/_locks/staging-cc44cd3a0fd01acc.lock for /Users/xf/Documents/Test/test/js/npmTest/a/node_modules/.staging
npm timing stage:executeActions Completed in 29ms
npm timing stage:rollbackFailedOptional Completed in 0ms
npm sill install runPostinstallTopLevelLifecycles
npm sill build a@1.0.0
npm info linkStuff a@1.0.0
npm sill linkStuff a@1.0.0 has /Users/xf/Documents/Test/test/js/npmTest as its parent node_modules
npm sill install a@1.0.0
npm info lifecycle a@1.0.0~install: a@1.0.0
npm sill postinstall a@1.0.0
npm info lifecycle a@1.0.0~postinstall: a@1.0.0
npm sill prepublish a@1.0.0
npm info lifecycle a@1.0.0~prepublish: a@1.0.0
npm info lifecycle a@1.0.0~prepare: a@1.0.0
npm timing stage:runTopLevelLifecycles Completed in 81ms
npm sill saveTree a@1.0.0 // 依赖的结构
npm sill saveTree └─┬ b@2.0.0
npm sill saveTree └── c@1.0.0
npm sill install saveToDependencies
npm verb saving []
npm verb shrinkwrap skipping write for package.json because there were no changes.
npm info lifecycle undefined~preshrinkwrap: undefined
npm info lifecycle a@1.0.0~shrinkwrap: a@1.0.0
npm verb shrinkwrap skipping write for package-lock.json because there were no changes.
npm info lifecycle a@1.0.0~postshrinkwrap: a@1.0.0
npm WARN a@1.0.0 No description
npm WARN a@1.0.0 No repository field.

npm sill install printInstalled
npm timing audit submit Completed in 511ms
npm http fetch POST 200 https://registry.yarnpkg.com/-/npm/v1/security/audits/quick 512ms
npm timing audit body Completed in 2ms
audited 2 packages in 0.565s
found 0 vulnerabilities

npm verb exit [ 0, true ]
npm timing npm Completed in 906ms
npm info ok

· 3 min read

最近朋友推荐我了解一个开源项目的升级,webpack从1.14.0 升级到目前最新的 v4.14.0

Project-WebCube 开源项目 (github被墙,需要fanqiang)

这个项目中使用了yarn 管理依赖,lerna 进行多项目依赖的统一化管理,解决大项目中依赖不同,版本更新出现的bug.

Project-WebCube/tree/master/packages/webcube > package.json 中yarn安装的webpack是1.14.0,但是在更新webpack当中运行报错 Cannot find module 'webpack/lib/removeAndDo' 然后发现extract-text-webpack-plugin插件最高只能支持webpack3 extract-text-webpack-plugin

Since webpack v4 the extract-text-webpack-plugin should not be used for css. Use mini-css-extract-plugin instead.

需要替换成 mini-css-extract-plugin插件使用 mini-css-extract-plugin

extract-text-webpack-plugin && mini-css-extract-plugin 区别

extract-text-webpack-plugin

Extract text from a bundle, or bundles, into a separate file.

extract-text-webpack-plugin 抽取到同一个文件夹下,名称不变

    var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: {
"script": "./src/entry.js",
"bundle": "./src/entry2.js",
},
...
module: {
loaders: [
{ test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader") }
]
},
plugins: [
new ExtractTextPlugin("[name].css")
]
}

但是这样配置的话所有分离的文件也会压缩到一个文件上

    plugins: [
new ExtractTextPlugin("[name].css", {allChunks: true})
]
  • mini-css-extract-plugin不能压缩到同一个文件夹,只能压缩到同一个文件中或者是压缩到js文件中,如此一来,优点是减少了请求,缺点也很明显,如果文件很大,打包过后js文件将会很大.
  • extract-text-webpack-plugin 可以实现多个文件抽离到同一个文件夹下,但是目前不支持webpack 4.X.X,官方推荐使用mini-css-extract-plugin
  • mini-css-extract-plugin如下配置打包,会把import './css/index.css' 文件打包压缩到/dist文件夹下的一个js文件中,然后通过script中的src源引入.

mini-css-extract-plugin

mini-css-extract-plugin 配置 抽离到同一个文件夹可以如下:

    module.exports = {
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
})
]
}

· 6 min read

概述

Node 应用由模块组成,采用 CommonJS 模块规范。

每个文件就是一个模块,有自己的作用域。在一个文件里面定义的变量、函数、类,都是私有的,对其他文件不可见。

CommonJS模块的特点如下:

  • 所有代码都运行在模块作用域,不会污染全局作用域。
  • 模块可以多次加载,但是只会在第一次加载时运行一次,然后运行结果就被缓存了,以后再加载,就直接读取缓存结果。要想让模块再次运行,必须清除缓存。
  • 模块加载的顺序,按照其在代码中出现的顺序。

module对象

Node内部提供一个Module构建函数。所有模块都是Module的实例。

function

    function Module(id, parent) {
this.id = id;
this.exports = {};
this.parent = parent;
// ...

每个模块内部,都有一个module对象,代表当前模块。它有以下属性。

  • module.id 模块的识别符,通常是带有绝对路径的模块文件名。
  • module.filename 模块的文件名,带有绝对路径。
  • module.loaded 返回一个布尔值,表示模块是否已经完成加载。
  • module.parent 返回一个对象,表示调用该模块的模块。
  • module.children 返回一个数组,表示该模块要用到的其他模块。
  • module.exports 表示模块对外输出的值。

module.exports属性

module.exports属性表示当前模块对外输出的接口,其他文件加载该模块,实际上就是读取module.exports变量。

demo

    var EventEmitter = require('events').EventEmitter;
module.exports = new EventEmitter();

setTimeout(function() {
module.exports.emit('ready');
}, 1000);

上面模块会在加载后1秒后,发出ready事件。其他文件监听该事件,可以写成下面这样。

    var a = require('./a');
a.on('ready', function() {
console.log('module a is ready');
});

exports变量

为了方便,Node为每个模块提供一个exports变量,指向module.exports。这等同在每个模块头部,有一行这样的命令。

AMD规范与CommonJS规范的兼容性

CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数。由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

    define(['package/lib'], function(lib){
function foo(){
lib.log('hello world!');
}

return {
foo: foo
};
});

AMD规范允许输出的模块兼容CommonJS规范,这时define方法需要写成下面这样:

    define(function (require, exports, module){
var someModule = require("someModule");
var anotherModule = require("anotherModule");

someModule.doTehAwesome();
anotherModule.doMoarAwesome();

exports.asplode = function (){
someModule.doTehAwesome();
anotherModule.doMoarAwesome();
};
});

require命令

基本用法

Node使用CommonJS模块规范,内置的require命令用于加载模块文件。

require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。如果没有发现指定模块,会报错。

模块的缓存

第一次加载某个模块时,Node会缓存该模块。以后再加载该模块,就直接从缓存取出该模块的module.exports属性。

    require('./example.js');
require('./example.js').message = "hello";
require('./example.js').message
// "hello"

所有缓存的模块保存在require.cache之中,如果想删除模块的缓存,可以像下面这样写。

    // 删除指定模块的缓存
delete require.cache[moduleName];

// 删除所有模块的缓存
Object.keys(require.cache).forEach(function(key) {
delete require.cache[key];
})

require.main

require方法有一个main属性,可以用来判断模块是直接执行,还是被调用执行。

直接执行的时候(node module.js),require.main属性指向模块本身。

    require.main === module
// true

模块的加载机制

CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个例子。

下面是一个模块文件lib.js。

    // lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};

然后,加载上面的模块。

    // main.js
var counter = require('./lib').counter;
var incCounter = require('./lib').incCounter;

console.log(counter); // 3
incCounter();
console.log(counter); // 3