前端基礎(chǔ)

Node.js

Node.js 是一個(gè)基于 Chrome V8 引擎的 JavaScript 運(yùn)行時(shí),讓 JavaScript 可以在脫離瀏覽器的環(huán)境下運(yùn)行。
Node.js 同時(shí)提供了很多常用操作方法和全局變量,可以在代碼中直接使用,比如 requireconsole.log,__dirname,setInterval,setTimeout 等等,可以認(rèn)為是前后端項(xiàng)目中的 JS 開(kāi)發(fā)包。
具體文檔參考:Node.js 中文網(wǎng)

NPM

npm 全稱為 Node Package Manager,是一個(gè)基于 Node.js 實(shí)現(xiàn)的包管理器,也是整個(gè) Node.js 社區(qū)最流行、支持的第三方模塊最多的包管理器。一般安裝完 Node.js 時(shí),默認(rèn)就帶了 npm,npm 常用命令如下:

npm init

創(chuàng)建并初始化一個(gè) package.json 文件,package.json 文件是一個(gè)純 JSON 文件,描述了項(xiàng)目中的一些信息,比如項(xiàng)目名稱,版本號(hào),第三方依賴,腳本信息等,一個(gè)簡(jiǎn)單的示例:

{
  "name": "my_package",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/ashleygwilliams/my_package.git"
  },
  "dependencies" :
  {
    "foo" : "1.0.0 - 2.9999.9999",
    "bar" : ">=1.0.2 <2.1.2",
    "PackageA": "1.0.0"
  },
  "devDependencies": {
    "coffee-script": "~1.6.3"
  },
  "peerDependencies": {
    "PackageB": "1.0.0"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "bugs": {
    "url": "https://github.com/ashleygwilliams/my_package/issues"
  },
  "homepage": "https://github.com/ashleygwilliams/my_package"
}

關(guān)于 peerDependencies,考慮如下使用場(chǎng)景

比如我們項(xiàng)目的依賴 PackageA,而 PackageA 依賴 PackageB,如果不使用 peerDependencies 話,那么安裝后的目錄是這樣的:

MyProject
|- node_modules
   |- PackageA
      |- node_modules
         |- PackageB

在項(xiàng)目中可以通過(guò) require(PackageA) 使用 A,但是無(wú)法直接通過(guò) require(PackageB) 使用 B,因?yàn)?Node 默認(rèn)在 node_modules 目錄下找

通過(guò)使用 peerDependencies 描述 PackageB,那么安裝后項(xiàng)目是這樣的:

MyProject
|- node_modules
   |- PackageA
   |- PackageB

參考:Package.json 各種依賴

npm install <package>

# 全局安裝
npm install -g jshint

# 本地安裝
npm install jshint

# 本地安裝,并在 package.json 中添加 dependencies 依賴
npm install jshint --save

# 本地安裝,并在 package.json 中添加 devDependencies 依賴
npm install jshint --save-dev

devDependencies 依賴是本地使用的依賴,不需要打包到項(xiàng)目中

npm uninstall <package>

# 卸載全局安裝包
npm uninstall -g lodash

# 卸載本地安裝包
npm uninstall lodash

# 卸載本地安裝包并從 package.json 中刪除 dependencies 依賴
npm uninstall --save lodash

# 卸載本地安裝包并從 package.json 中刪除 devDependencies 依賴
npm uninstall --save-dev lodash

npm update <package>

# 更新全局包
npm update -g lodash

# 更新本地 package.json 中制定的依賴包
npm update

npm run-script <command>

別名 npm run,執(zhí)行 package.json 中定義的腳本,對(duì)于 test, start, restart, stop 名稱,可以省略 run,

npm start
npm run start

npm run build

需要注意的是,對(duì)于本地命令工具,npm 默認(rèn)會(huì)對(duì)腳本添加 node_modules/.bin 路徑,不需要自己顯示指定

{
    "scripts": {
        "test": "tap test/\*.js",
        "test": "node_modules/.bin/tap test/\*.js" # 不需要這么寫(xiě)
    }
}

Webpack

webpack 是一個(gè)現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包器(module bundler)。當(dāng) webpack 處理應(yīng)用程序時(shí),它會(huì)遞歸地構(gòu)建一個(gè)依賴關(guān)系圖(dependency graph),其中包含應(yīng)用程序需要的每個(gè)模塊,然后將所有這些模塊打包成一個(gè)或多個(gè) bundle 文件。

安裝

# 全局安裝
npm install -g webpack

# 安裝到當(dāng)前項(xiàng)目目錄(一般使用這種方式)
npm install --save-dev webpack

使用

新建項(xiàng)目 WebpackDemo:

WebpackDemo
  |- node_modules
  |- app
    |- main.js
  |- public
    |- index.html
  |- package.json

基礎(chǔ)用法

# {extry file} 入口文件的路徑,本文中就是上述main.js的路徑,
# {destination for bundled file} 打包文件的存放路徑
webpack {entry file} {destination for bundled file}

# 示例
node_modules/.bin/webpack app/main.js public/bundle.js

配置文件 webpack.config.js

通過(guò)創(chuàng)建 webpack.config.js 配置文件,來(lái)簡(jiǎn)化 webpack 的使用。
首先先了解 webpack 的四個(gè)核心概念:entry,output,loader,plugins

entry

entry 指示 webpack 應(yīng)該使用哪個(gè)模塊,來(lái)作為構(gòu)建其內(nèi)部依賴圖的開(kāi)始,默認(rèn)值為 ./src。
進(jìn)入入口起點(diǎn)后,webpack 會(huì)找出有哪些模塊和庫(kù)是入口起點(diǎn)(直接和間接)依賴的。每個(gè)依賴項(xiàng)隨即被處理,最后輸出到稱之為 bundles 的文件中。

module.exports = {
  entry: './app/main.js'
};

output

output 屬性告訴 webpack 在哪里輸出它所創(chuàng)建的 bundles,以及如何命名這些文件,默認(rèn)值為 ./dist?;旧?,整個(gè)應(yīng)用程序結(jié)構(gòu),都會(huì)被編譯到你指定的輸出路徑的文件夾中。你可以通過(guò)在配置中指定一個(gè) output 字段,來(lái)配置這些處理過(guò)程:

module.exports = {
  entry:  __dirname + "/app/main.js",//已多次提及的唯一入口文件
  output: {
    path: __dirname + "/public",//打包后的文件存放的地方
    filename: "bundle.js"http://打包后輸出文件的文件名
  }
}

注:“__dirname” 是 node.js 中的一個(gè)全局變量,它指向當(dāng)前執(zhí)行腳本所在的目錄。

有了上面這個(gè)配置文件后,之前的命令就可以改成:

node_modules/.bin/webpack

結(jié)合前面講的 package.json,通過(guò)配置 scripts 字段可以進(jìn)一步簡(jiǎn)化:

{
  "name": "webpack-sample-project",
  "version": "1.0.0",
  "scripts": {
    "start": "webpack" // 這里不需要指定路徑,Node 自動(dòng)會(huì)從 node_modules/.bin 目錄下找
  },
  "devDependencies": {
    "webpack": "3.10.0"
  }
}

現(xiàn)在我們打包只需要輸入

npm start

前面說(shuō)過(guò),start 是一個(gè)特殊的命令,不需要加 run

loader

loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以將所有類型的文件轉(zhuǎn)換為 webpack 能夠處理的有效模塊,然后你就可以利用 webpack 的打包能力,對(duì)它們進(jìn)行處理。

通過(guò)使用不同的loader,webpack有能力調(diào)用外部的腳本或工具,實(shí)現(xiàn)對(duì)不同格式的文件的處理,比如說(shuō)分析轉(zhuǎn)換scss為css,或者把下一代的JS文件(ES6,ES7)轉(zhuǎn)換為現(xiàn)代瀏覽器兼容的JS文件,對(duì)React的開(kāi)發(fā)而言,合適的Loaders可以把React的中用到的JSX文件轉(zhuǎn)換為JS文件。

本質(zhì)上,webpack loader 將所有類型的文件,轉(zhuǎn)換為應(yīng)用程序的依賴圖(和最終的 bundle)可以直接引用的模塊。

loaders 需要單獨(dú)安裝并且需要在 webpack.config.js 中的 modules 關(guān)鍵字下進(jìn)行配置,Loaders 的配置包括以下幾方面:

  • test:一個(gè)用以匹配loaders所處理文件的拓展名的正則表達(dá)式(必須)
  • loader:loader的名稱(必須)
  • include/exclude:手動(dòng)添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選);
  • query:為loaders提供額外的設(shè)置選項(xiàng)(可選)

安裝對(duì)應(yīng)的 loader

npm install --save-dev css-loader
npm install --save-dev ts-loader

webpack.config.js

module.exports = {
  module: {
    rules: [
      { test: /\.css$/, use: 'css-loader' },
      { test: /\.ts$/, use: 'ts-loader' }
    ]
  }
};
常見(jiàn) loader

Babel
Babel其實(shí)是一個(gè)編譯JavaScript的平臺(tái),它可以編譯代碼幫你達(dá)到以下目的:

  • 讓你能使用最新的JavaScript代碼(ES6,ES7...),而不用管新標(biāo)準(zhǔn)是否被當(dāng)前使用的瀏覽器完全支持;
  • 讓你能使用基于JavaScript進(jìn)行了拓展的語(yǔ)言,比如React的JSX;

Babel 其實(shí)是幾個(gè)模塊化的包,其核心功能位于稱為babel-core 的 npm 包中,webpack 可以把其不同的包整合在一起使用,對(duì)于每一個(gè)你需要的功能或拓展,你都需要安裝單獨(dú)的包(用得最多的是解析Es6的 babel-env-preset 包和解析 JSX 的 babel-preset-react 包)。

安裝 babel

npm install --save react react-dom

npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react

webpack.config.js

module.exports = {
    entry: __dirname + "/app/main.js",//已多次提及的唯一入口文件
    output: {
        path: __dirname + "/public",//打包后的文件存放的地方
        filename: "bundle.js"http://打包后輸出文件的文件名
    },
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader",
                    options: {
                        presets: [
                            "env", "react"
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
};

通過(guò)上面配置,我們就可以在項(xiàng)目中使用 React 以及 JSX 語(yǔ)法了

關(guān)于 Babel,參考 Babel 中文文檔

css-loaderstyle-loader
css-loader 使你能夠使用類似 @import 和 url(...) 的方法實(shí)現(xiàn) require() 的功能,style-loader 將所有的計(jì)算后的樣式加入頁(yè)面中,二者組合在一起使你能夠把樣式表嵌入webpack打包后的JS文件中。

# 安裝
npm install --save-dev style-loader css-loader
// 使用
module.exports = {

   ...
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: {
                    loader: "babel-loader"
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: "style-loader"
                    }, {
                        loader: "css-loader"
                    }
                ]
            }
        ]
    }
};

請(qǐng)注意這里對(duì)同一個(gè)文件引入多個(gè)loader的方法。

CSS module
被稱為 CSS modules 的技術(shù)意在把 JS 的模塊化思想帶入 CSS 中來(lái),通過(guò) CSS 模塊,所有的類名,動(dòng)畫(huà)名默認(rèn)都只作用于當(dāng)前模塊。Webpack 對(duì) CSS 模塊化提供了非常好的支持,只需要在 CSS loader 中進(jìn)行簡(jiǎn)單配置即可,然后就可以直接把 CSS 的類名傳遞到組件的代碼中,這樣做有效避免了全局污染。具體的代碼如下:

{
    test: /\.css$/,
    use: [
    {
        loader: "style-loader"
    }, 
    {
        loader: "css-loader",
        options: {
            modules: true, // 指定啟用css modules
            localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的類名格式
        }
    }]
}

使用示例:

/* Greeter.css */
.root {
  background-color: #eee;
  padding: 10px;
  border: 3px solid #ccc;
}
/* Greeter.js */
import React, {Component} from 'react';
import config from './config.json';
import styles from './Greeter.css';//導(dǎo)入

class Greeter extends Component{
  render() {
    return (
      <div className={styles.root}> //使用cssModule添加類名的方法
        {config.greetText}
      </div>
    );
  }
}
export default Greeter

CSS預(yù)處理器
Sass 和 Less 之類的預(yù)處理器是對(duì)原生 CSS 的拓展,它們?cè)试S你使用類似于 variables, nesting, mixins, inheritance 等不存在于 CSS 中的特性來(lái)寫(xiě) CSS,CSS 預(yù)處理器可以這些特殊類型的語(yǔ)句轉(zhuǎn)化為瀏覽器可識(shí)別的CSS語(yǔ)句,只需要在webpack里使用相關(guān) loaders 進(jìn)行配置就可以使用了,以下是常用的CSS 處理loaders:

  • Less Loader
  • Sass Loader
  • Stylus Loader

plugins

插件(Plugins)是用來(lái)拓展 Webpack 功能的,它們會(huì)在整個(gè)構(gòu)建過(guò)程中生效,執(zhí)行相關(guān)的任務(wù)。

Loaders 和 Plugins 常常被弄混,但是他們其實(shí)是完全不同的東西,loaders是在打包構(gòu)建過(guò)程中用來(lái)處理源文件的(JSX,Scss,Less..),一次處理一個(gè),plugin 并不直接操作單個(gè)文件,它直接對(duì)整個(gè)構(gòu)建過(guò)程其作用,比如打包優(yōu)化,壓縮,重新定義變量等。

Webpack 有很多內(nèi)置插件,同時(shí)也有很多第三方插件,可以讓我們完成更加豐富的功能。

插件使用
  1. 通過(guò) npm 安裝(非內(nèi)置插件)
  2. 配置 webpack.config.js 文件
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通過(guò) npm 安裝
const webpack = require('webpack'); // 用于訪問(wèn)內(nèi)置插件

const config = {
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({template: './src/index.html'}),
    new webpack.BannerPlugin('版權(quán)所有,翻版必究')
  ]
};

module.exports = config;
插件介紹

HtmlWebpackPlugin
這個(gè)插件的作用是依據(jù)一個(gè)簡(jiǎn)單的index.html模板,生成一個(gè)自動(dòng)引用你打包后的JS文件的新index.html。這在每次生成的js文件名稱不同時(shí)非常有用(比如添加了hash值)。

Hot Module Replacement
許你在修改組件代碼后,自動(dòng)刷新實(shí)時(shí)預(yù)覽修改后的效果。

其他優(yōu)化插件
webpack 提供了一些在發(fā)布階段非常有用的優(yōu)化插件,它們大多來(lái)自于 webpack 社區(qū),可以通過(guò) npm 安裝,通過(guò)以下插件可以完成產(chǎn)品發(fā)布階段所需的功能

  • OccurenceOrderPlugin :為組件分配ID,通過(guò)這個(gè)插件webpack可以分析和優(yōu)先考慮使用最多的模塊,并為它們分配最小的ID
  • UglifyJsPlugin:壓縮JS代碼;
  • ExtractTextPlugin:分離CSS和JS文件

其他功能

Source Maps

開(kāi)發(fā)總是離不開(kāi)調(diào)試,方便的調(diào)試能極大的提高開(kāi)發(fā)效率,不過(guò)有時(shí)候通過(guò)打包后的文件,你是不容易找到出錯(cuò)了的地方,對(duì)應(yīng)的你寫(xiě)的代碼的位置的,Source Maps就是來(lái)幫我們解決這個(gè)問(wèn)題的。

通過(guò)簡(jiǎn)單的配置,webpack就可以在打包時(shí)為我們生成的source maps,這為我們提供了一種對(duì)應(yīng)編譯文件和源文件的方法,使得編譯后的代碼可讀性更高,也更容易調(diào)試。

在webpack的配置文件中配置source maps,需要配置devtool,它有以下四種不同的配置選項(xiàng),各具優(yōu)缺點(diǎn),描述如下:
[圖片上傳失敗...(image-ab92c1-1607478774018)]

module.exports = {
  devtool: 'eval-source-map',
  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  }
}
構(gòu)建本地服務(wù)器

Webpack提供一個(gè)可選的本地開(kāi)發(fā)服務(wù)器,這個(gè)本地服務(wù)器基于 node.js 構(gòu)建,可以實(shí)現(xiàn)監(jiān)聽(tīng)修改自動(dòng)刷新的功能,不過(guò)它是一個(gè)單獨(dú)的組件,在 webpack中進(jìn)行配置之前需要單獨(dú)安裝它作為項(xiàng)目依賴:

npm install --save-dev webpack-dev-server
module.exports = {
  devtool: 'eval-source-map',

  entry:  __dirname + "/app/main.js",
  output: {
    path: __dirname + "/public",
    filename: "bundle.js"
  },

  devServer: {
    contentBase: "./public",//本地服務(wù)器所加載的頁(yè)面所在的目錄
    historyApiFallback: true,//不跳轉(zhuǎn)
    inline: true//實(shí)時(shí)刷新
  } 
}

package.json

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack",
    "server": "webpack-dev-server --open"
  },

在終端中輸入npm run server即可在本地的8080端口查看結(jié)果

發(fā)布

發(fā)布階段主要是做一些優(yōu)化,比如代碼壓縮,去掉調(diào)試等,dev 和 release 可以提供不同的 webpack.config.js 文件。

參考

Webpack 中文文檔

Webpack 入門(mén)

npm

Babel

Node.js

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容