webpack路線
webpack的意義
- 模塊化的思想(模塊打包器)
- scss、less瘩绒、typescript的預(yù)處理器以及l(fā)oader加載工具
webpack的安裝
webpack基于node環(huán)境, 具體node的安裝就不說了, 下面主要是webpack的安裝
// 全局安裝
npm install -g webpack
// 安裝到項目上
npm install --save-dev webpack
webpack的使用
- 新建一個webpack的文件夾
mkdir webpack-demo
cd webpack-demo
npm init
npm install --save-dev webpack webpack-cli
說明: webpack4將webpack的命令都遷移到webpack-cli, 所以如果你用的webpack版本在4.0一下可以省略安裝webpack-cli
- 新建文件夾app和public,public放入一個公共的index.html文件, 新建app文件夾的main.js和greeter.js
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack 簡單練習(xí)</title>
</head>
<body>
<div id="root"></div>
<script src="./bundle.js"></script>
</body>
</html>
main.js
let greeter = require('./greeter.js');
document.querySelector('#root').append(greeter());
greeter.js
module.exports = function() {
let greeter = document.createElement('div');
greeter.innerText = '測試webpack';
return greeter;
};
- 現(xiàn)在我們可以使用webpack命令打包文件
// 全局安裝webpack
webpack app/main.js public/bundle.js
// 非全局安裝webpack
node_modules/.bin/webpack app/main.js public/bundle.js
- webpack成功之后產(chǎn)生一個bundle.js文件
D:\study\webpack\webpack-demo>webpack
Hash: a891a5964dd833cfdb21
Version: webpack 4.32.2
Time: 97ms
Built at: 2019-05-29 16:20:18
Asset Size Chunks Chunk Names
bundle.js 2.2 KiB 0 [emitted] main
Entrypoint main = bundle.js
[0] ./app/main.js 90 bytes {0} [built]
[1] ./app/greeter.js 136 bytes {0} [built]
- 每次打包命令挺煩, 下面通過配置文件使用webpack,新建webpack.config.js文件
module.exports = {
entry: __dirname + "/app/main.js",//唯一入口文件
output: {
path: __dirname + "/public",//打包后的文件存放的地方
filename: "bundle.js"http://打包后輸出文件的文件名
}
}
- 配置package.json文件
{
"name": "webpack-sample-project",
"version": "1.0.0",
"description": "Sample webpack project",
"scripts": {
"start": "webpack" // 修改的是這里,JSON文件不支持注釋,引用時請清除
},
"author": "zhang",
"license": "ISC",
"devDependencies": {
"webpack": "3.10.0"
}
}
- 以后可以使用命令可以直接打包
npm run start 或者 npm start
webpack的配置和強(qiáng)大功能
生成Source Maps(使調(diào)試更容易)
開發(fā)總是離不開調(diào)試珍坊,方便的調(diào)試能極大的提高開發(fā)效率侵状,不過有時候通過打包后的文件赞弥,你是不容易找到出錯了的地方,對應(yīng)的你寫的代碼的位置的趣兄,Source Maps就是來幫我們解決這個問題的绽左。
通過簡單的配置,webpack就可以在打包時為我們生成的source maps艇潭,這為我們提供了一種對應(yīng)編譯文件和源文件的方法拼窥,使得編譯后的代碼可讀性更高,也更容易調(diào)試蹋凝。
devtool選項
配置結(jié)果
source-map
在一個單獨(dú)的文件中產(chǎn)生一個完整且功能完全的文件鲁纠。這個文件具有最好的source map,但是它會減慢打包速度鳍寂;
cheap-module-source-map
在一個單獨(dú)的文件中生成一個不帶列映射的map改含,不帶列映射提高了打包速度,但是也使得瀏覽器開發(fā)者工具只能對應(yīng)到具體的行迄汛,不能對應(yīng)到具體的列(符號)捍壤,會對調(diào)試造成不便骤视;
eval-source-map
使用eval打包源文件模塊,在同一個文件中生成干凈的完整的source map鹃觉。這個選項可以在不影響構(gòu)建速度的前提下生成完整的sourcemap专酗,但是對打包后輸出的JS文件的執(zhí)行具有性能和安全的隱患。在開發(fā)階段這是一個非常好的選項盗扇,在生產(chǎn)階段則一定不要啟用這個選項笼裳;
cheap-module-eval-source-map
這是在打包文件時最快的生成source map的方法,生成的Source Map 會和打包后的JavaScript文件同行顯示粱玲,沒有列映射躬柬,和eval-source-map選項具有相似的缺點(diǎn);
對小到中型的項目中抽减,eval-source-map是一個很好的選項允青,再次強(qiáng)調(diào)你只應(yīng)該開發(fā)階段使用它,我們繼續(xù)對上文新建的webpack.config.js
配置eval-source-map,配置完webpack.config.js如下:
module.exports = {
devtool: 'eval-source-map',
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}
}
使用webpack構(gòu)建本地服務(wù)器
安裝npm install --save-dev webpack-dev-server
配置webpack-dev-server到webpack.config.js,如下:
module.exports = {
devtool: 'eval-source-map', // 方便調(diào)試
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服務(wù)器
devServer: {
contentBase: './public', // 默認(rèn)webpack-dev-server會為根文件夾提供本地服務(wù)器卵沉,如果想為另外一個目錄下的文件提供本地服務(wù)器颠锉,應(yīng)該在這里設(shè)置其所在目錄
inline: true, // 設(shè)置為true,當(dāng)源文件改變時會自動刷新頁面
historyApiFallback: true, //在開發(fā)單頁應(yīng)用時非常有用史汗,它依賴于HTML5 history API琼掠,如果設(shè)置為true,所有的跳轉(zhuǎn)將指向index.html
port: 7010 // 設(shè)置默認(rèn)監(jiān)聽端口停撞,如果省略瓷蛙,默認(rèn)為”8080“
},
在package.json中的scripts對象中添加如下命令,用以開啟本地服務(wù)器:
"scripts": {
"start": "webpack",
"server": "webpack-dev-server --open"
},
在項目的根目錄下運(yùn)行npm run server啟動項目
webpack的loader處理器
loader處理的問題
- loader是從右向左的取值
- loader 支持鏈?zhǔn)絺鬟f,鏈中的每個 loader 會將轉(zhuǎn)換應(yīng)用在已處理過的資源上
- loader 也可以內(nèi)聯(lián)顯示指定
- loader 可以是同步的戈毒,也可以是異步的
- loader 運(yùn)行在 Node.js 中艰猬,并且能夠執(zhí)行任何 Node.js 能做到的操作
- loader 可以通過 options 對象配置
- 除了常見的通過 package.json 的 main 來將一個 npm 模塊導(dǎo)出為 loader,還可以在 module.rules 中使用 loader 字段直接引用一個模塊
- loader 能夠產(chǎn)生額外的任意文件
常用的loader
- style-loader 將css添加到DOM的內(nèi)聯(lián)樣式標(biāo)簽style里
- css-loader 允許將css文件通過require的方式引入埋市,并返回css代碼
- less-loader 處理less
- sass-loader 處理sass
- postcss-loader 用postcss來處理CSS
- autoprefixer-loader 處理CSS3屬性前綴冠桃,已被棄用,建議直接使用postcss
- file-loader 分發(fā)文件到output目錄并返回相對路徑
- url-loader 和file-loader類似道宅,但是當(dāng)文件小于設(shè)定的limit時可以返回一個Data Url
- html-minify-loader 壓縮HTML
- babel-loader 用babel來轉(zhuǎn)換ES6文件到ES5
import Styles from 'style-loader!css-loader?modules!./style.css'
use: [
{ loader: 'style-loader' },
{
loader: 'loader-css',
options: {
modules: true,
minimize: true
}
},
{ loader: 'sass-loader' }
]
以babel-loader為例
安裝
npm install --save-dev babel-core babel-loader babel-preset-env babel-preset-react
配置webpack.config.js
/**
* __dirname node.js的全局變量,指向當(dāng)前執(zhí)行腳本的所在目錄
* @type {{entry: string, output: {path: string, filename: string}}}
*/
module.exports = {
devtool: 'eval-source-map', // 方便調(diào)試
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服務(wù)器
devServer: {
contentBase: './public', // 默認(rèn)webpack-dev-server會為根文件夾提供本地服務(wù)器食听,如果想為另外一個目錄下的文件提供本地服務(wù)器,應(yīng)該在這里設(shè)置其所在目錄
inline: true, // 設(shè)置為true污茵,當(dāng)源文件改變時會自動刷新頁面
historyApiFallback: true, //在開發(fā)單頁應(yīng)用時非常有用樱报,它依賴于HTML5 history API,如果設(shè)置為true省咨,所有的跳轉(zhuǎn)將指向index.html
port: 7010 // 設(shè)置默認(rèn)監(jiān)聽端口肃弟,如果省略,默認(rèn)為”8080“
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
}
]
}
};
Babel其實是幾個模塊化的包,其核心功能位于稱為babel-core的npm包中笤受,webpack可以把其不同的包整合在一起使用穷缤,對于每一個你需要的功能或拓展,你都需要安裝單獨(dú)的包(用得最多的是解析Es6的babel-env-preset包和解析JSX的babel-preset-react包)箩兽。
安裝 React 和 React-DOM
npm install --save react react-dom
插件的使用
Loaders和Plugins常常被弄混津肛,但是他們其實是完全不同的東西,可以這么來說汗贫,loaders是在打包構(gòu)建過程中用來處理源文件的(JSX身坐,Scss,Less..)落包,一次處理一個部蛇,插件并不直接操作單個文件,它直接對整個構(gòu)建過程其作用咐蝇。
插件的使用
module.exports = {
...
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: "babel-loader"
},
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
modules: true
}
}, {
loader: "postcss-loader"
}
]
}
]
},
plugins: [
new webpack.BannerPlugin('版權(quán)所有涯鲁,翻版必究')
],
};
HtmlWebpackPlugin
這個插件的作用是依據(jù)一個簡單的index.html模板,生成一個自動引用你打包后的JS文件的新index.html有序。這在每次生成的js文件名稱不同時非常有用(比如添加了hash值)抹腿。
npm install --save-dev html-webpack-plugin
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/**
* __dirname node.js的全局變量,指向當(dāng)前執(zhí)行腳本的所在目錄
* @type {{entry: string, output: {path: string, filename: string}}}
*/
module.exports = {
devtool: 'eval-source-map', // 方便調(diào)試
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/build",
filename: "bundle.js"
},
// webpack-dev-server 配置本地服務(wù)器
devServer: {
contentBase: './public', // 默認(rèn)webpack-dev-server會為根文件夾提供本地服務(wù)器,如果想為另外一個目錄下的文件提供本地服務(wù)器旭寿,應(yīng)該在這里設(shè)置其所在目錄
inline: true, // 設(shè)置為true警绩,當(dāng)源文件改變時會自動刷新頁面
historyApiFallback: true, //在開發(fā)單頁應(yīng)用時非常有用,它依賴于HTML5 history API盅称,如果設(shè)置為true肩祥,所有的跳轉(zhuǎn)將指向index.html
port: 7010 // 設(shè)置默認(rèn)監(jiān)聽端口,如果省略微渠,默認(rèn)為”8080“
},
module: {
rules: [
{
test: /(\.jsx|\.js)$/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react']
}
}
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader'
}, {
loader: 'css-loader',
options: {
modules: true, // 指定啟用css modules
localIdentName: '[name]__[local]--[hash:base64:5]' // 指定css的類名格式
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: '初始化webpack',
template: __dirname + '/app/index.tmpl.html'
})
]
};
打包
npm run server
Hot Module Replacement
Hot Module Replacement(HMR)也是webpack里很有用的一個插件搭幻,它允許你在修改組件代碼后,自動刷新實時預(yù)覽修改后的效果逞盆。
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack",
"server": "webpack-dev-server --open --hot"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.5.1",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.8",
"html-webpack-plugin": "^3.2.0",
"postcss-loader": "^3.0.0",
"style-loader": "^0.23.1",
"webpack": "^4.32.2",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.4.1"
},
"dependencies": {
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}