模塊化是一種主流的組織方式,它經過把咱們的複雜代碼按照功能的不一樣劃分爲不一樣的模塊,單獨的維護這種方式,提升咱們的開發效率,下降維護成本。javascript
模塊化只是思想,不包含具體的實現。css
CommonJS in Node.jshtml
Es Modules in Browers前端
CommonJSvue
ES Modulesjava
ESM中沒有CommonJS中的那些模塊全局變量node
webpack做爲目前最主流的前端模塊打包器,提供了一整套前端項目模塊化方案。react
webpack4之後的版本它支持零配置的方式直接啓動打包,打包過程會按照約定src/index.js
=>dist/main.js
jquery
const path = require('path')
module.exports = {
//去指定webpack打包入口文件的路徑
entry: './src/main.js',
//設置輸出文件的配置
output: {
//輸出文件的名稱
filename: 'bundle.js',
//輸出文件的路徑(絕對路徑)
path: path.join(__dirname, 'dist')
}
}
複製代碼
webpack4新增工做模式作法,這種用法大大的簡化了webpack配置的複雜程度,能夠把它理解成針對於不一樣環境的幾組預設配置webpack
module.exports = {
//工做模式
mode: 'development'
}
複製代碼
總體生成的代碼是一個當即執行的函數,這個函數接受一個modules的參數,調用時傳入了一個數組
展開這個數組,數組中的每個元素都是一個參數列表相同的函數,這裏的函數對於的是源代碼當中的模塊,每個模塊最終都會包裹到這些函數當中,從而實現模塊的私有做用域
Loader是Webpack的核心特性,藉助於Loader就能夠加載任何類型的資源。
以加載css爲例,首先安裝css-loader來轉換css文件,在安裝style-loader將css-loader轉換事後的結果經過style標籤的形式添加到頁面上,webpack配置以下:
// 配置對象
module: {
//其餘資源模塊加載規則
rules: [{
//匹配打包過程當中遇到的文件路徑
test: /.css$/,
//匹配文件打包過程當中用的loader 配置了多個loader執行順序是從後往前執行
use: [
'style-loader', //把css-loader轉換後的結果經過style標籤的形式添加到頁面上
'css-loader' //處理css文件的加載器
]
}]
}
複製代碼
webpack的打包入口通常是javascript文件,通常打包入口是應用程序的運行入口,目前而言,前端應用中的業務是由JavaScript來驅動的。
import './heading.css'
export default () => {
const element = document.createElement('h2')
element.textContent = 'Hello world'
element.classList.add('heading')
element.addEventListener('click', () => {
alert('Hello webpack')
})
return element
}
複製代碼
file-loader 處理文件加載器
文件加載器的工做過程
webpack在打包時遇到咱們的圖片文件,根據咱們配置文件當中的配置匹配到對應的文件加載器,此時文件加載器開始工做,它先將咱們導入的文件拷貝到輸出目錄,而後將輸出目錄的路徑做爲當前模塊的返回值返回,這樣對於咱們的應用來講所須要的資源就被髮布出來了,同時咱們能夠經過模塊的導出成員拿到咱們資源的訪問路徑
{
test: /.png$/,
use: 'file-loader' //文件加載器
}
複製代碼
Data URIs是一種當前URL就能表示文件內容的方式,這種URL中的文本就已經包含了文件內容,咱們在使用這種URL的時候就不會去發送任何的HTTP請求
url-loader Data URI加載器
{
test: /.png$/,
use: 'url-loader', //Data URLs加載器
//配置選項
options: {
limit: 10 * 1024 // 只將10kb如下的文件用url-loader處理
}
}
複製代碼
最佳實踐
注意事項:對於超出大小的文件url loader會去調用file loader,因此仍是要安裝fileloader
webpack的資源加載器相似生活當中工廠裏面的生產車間,它是用來處理和加工打包過程看成的資源文件
因爲webpack默認就能處理咱們代碼當中的import/export,因此很天然的有人認爲webpack會自動編譯es6的代碼,由於模塊打包須要,因此處理import/export,除此以外並不能處理代碼當中其餘的es6特性,若是咱們須要在打包過程看成處理其餘es6特性的轉換,咱們須要爲js文件添加一個額外的編譯性loader
babel-loader,一個編譯型loader,用來處理es6特性的轉換
{
test: /.js$/,
use: {
loader: 'babel-loader', //處理es6代碼看成的新特性
options: {
//babel只是一個轉換js代碼的平臺,在平臺轉換過程當中須要額外的插件
presets: ['@babel/preset-env']
}
}
}
複製代碼
webpack只是打包工具
加載器能夠用來編譯轉換代碼
{
test: /.html$/,
use: {
loader: 'html-loader', //html解析器
options: {
// html加載的時候對頁面上的一些屬性作一些額外處理
attrs: [
'img:src', //默認
'a:href'
]
}
}
}
複製代碼
markdown-loader 在代碼當中直接導入markdown文件
實現方式
const marked = require('marked') //markdown解析模塊
module.exports = source => {
const html = marked(source)
//返回的類型必定要是js代碼
// return 'console.log("hello ~")'
//直接拼接html當中存在的換行符和內部的引號拼接在一塊兒可能引發語法錯誤
// return `module.exports="${html}"`
//CommonJS方式導出字符串
// return `module.exports=${JSON.stringify(html)}`
//ES Modules方式導出
// return `export default ${JSON.stringify(html)}`
//返回html字符串交給下一個loader處理
return html
}
複製代碼
{
test: /.md$/,
use: [
'html-loader',
'./markdown-loader'
]
}
複製代碼
工做原理
//配置插件
plugins: [
//清理輸出目錄
new CleanWebpackPlugin()
]
複製代碼
//配置插件
plugins: [
//清理輸出目錄
new CleanWebpackPlugin(),
//自動生成index.html
new HtmlWebpackPlugin({
title: 'Webpack Plugin Sample',
meta: {
viewport: 'width=device-width'
},
template: './index.html'
}),
//用於生成about.html
new HtmlWebpackPlugin({
filename: 'about.html'
})
]
複製代碼
class MyPlugin {
apply(compiler) {
console.log('My Plugin 啓動')
compiler.hooks.emit.tap('MyPlugin', compilation => {
//compilation能夠理解爲這次打包的上下文
for (const name in compilation.assets) {
// console.log(compilation.assets[name].source())
//判斷是不是js文件
if (name.endsWith('.js')) {
//獲取文件的內容
const contents = compilation.assets[name].source()
//將註釋替換成空
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
//將最終結果覆蓋原有的內容當中
compilation.assets[name] = {
//返回新的內容
source: () => withoutComments,
//返回內容大小,這個方式是webpack內部要求必須的方法
size: () => withoutComments.length
}
}
}
})
}
}
複製代碼
//配置插件
plugins: [
//自定義插件 刪除生成的js文件當中的註釋
new MyPlugin()
]
複製代碼
跨域資源共享(CORS),使用CORS的前提是API必須支持,並非任何狀況下API都應該支持
同源部署(域名端口協議一致)
開發階段接口跨域
webpack dev server支持配置代理
用法
// webpack dev server的配置選項
devServer: {
//靜態資源文件路徑
contentBase: ['./public'],
//代理對象
proxy: {
'/api': {
//http://localhost:8080/api/users =>https://api.github.com/api/users
target: 'https://api.github.com',
//http://localhost:8080/api/users =>https://api.github.com/users
//代理路徑重寫
publicPath: {
'^/api': ''
},
//不能使用 localhost:8080 做爲請求 github 的主機名
changeOrigin: true //以實際代理請求的主機名去請求
}
}
}
複製代碼
//配置開發過程當中的輔助工具
devtool: 'source-map'
複製代碼
devtool | 構建速度 | 從新構建速度 | 生產環境 | 品質(quality) |
(none) | 很是快速 | 很是快速 | yes | 打包後的代碼 |
eval | 很是快速 | 很是快速 | no | 生成後的代碼 |
eval-cheap-source-map | 比較快 | 快速 | no | 轉換過的代碼(僅限行) |
eval-cheap-module-source-map | 中等 | 快速 | no | 原始源代碼(僅限行) |
eval-source-map | 慢 | 比較快 | no | 原始源代碼 |
eval-nosources-source-map | ||||
eval-nosources-cheap-source-map | ||||
eval-nosources-cheap-module-source-map | ||||
cheap-source-map | 比較快 | 中等 | yes | 轉換過的代碼(僅限行) |
cheap-module-source-map | 中等 | 比較慢 | yes | 原始源代碼(僅限行) |
inline-cheap-source-map | 比較快 | 中等 | no | 轉換過的代碼(僅限行) |
inline-cheap-module-source-map | 中等 | 比較慢 | no | 原始源代碼(僅限行) |
inline-source-map | 慢 | 慢 | no | 原始源代碼 |
inline-nosources-source-map | ||||
inline-nosources-cheap-source-map | ||||
inline-nosources-cheap-module-source-map | ||||
source-map | 慢 | 慢 | yes | 原始源代碼 |
hidden-source-map | 慢 | 慢 | yes | 原始源代碼 |
hidden-nosources-source-map | ||||
hidden-nosources-cheap-source-map | ||||
hidden-nosources-cheap-module-source-map | ||||
hidden-cheap-source-map | ||||
hidden-cheap-module-source-map | ||||
nosources-source-map | 慢 | 慢 | yes | 無源代碼內容 |
nosources-cheap-source-map | ||||
nosources-cheap-module-source-map |
HMR集成在webpack-dev-server中
//熱更新插件
new webpack.HotModuleReplacementPlugin()
複製代碼
module.hot.accept('./editor', () => {
console.log('editor模塊更新了,須要這裏手動處理熱更新')
})
複製代碼
//存儲最後一次更新的值
let lastEditor = editor
module.hot.accept('./editor', () => {
console.log('editor模塊更新了,須要這裏手動處理熱更新', lastEditor.value)
//拿到編輯的內容
const value = lastEditor.value
//移除原來的元素
document.body.removeChild(editor)
//建立一個新的元素
const newEditor = createEditor()
//將原來的只添加到新元素的值當中 避免原來的值丟失
newEditor.value = value
//將新元素追加到頁面
document.body.appendChild(newEditor)
//記錄最新的元素 不然下次找不到這個元素了
lastEditor = newEditor
})
複製代碼
//圖片的熱處理替換
module.hot.accept('./01.png', () => {
img.src = background
console.log(background)
})
複製代碼
/** * 不一樣的環境返回不一樣的配置 * @param {*} env CLI傳遞的環境名參數 * @param {*} argv 運行CLI過程當中所傳遞的全部參數 */
module.exports = (env, argv) => {
//開發環境的配置
const config = {
//工做模式
mode: 'none',
//去指定webpack打包入口文件的路徑
entry: './src/main.js',
//設置輸出文件的配置
output: {
//輸出文件的名稱
filename: 'bundle.js',
//輸出文件的路徑(絕對路徑)
path: path.join(__dirname, 'dist'),
//打包事後的文件具體存放位置
// publicPath: 'dist/'
},
// webpack dev server的配置選項
devServer: {
//開啓熱更新 報錯會從新刷新瀏覽器,不易調試
hot: true,
//不管代碼是否被處理了熱替換,瀏覽器都不會自動刷新
hotOnly: true,
//靜態資源文件路徑
contentBase: ['./public'],
//代理對象
proxy: {
'/api': {
//http://localhost:8080/api/users =>https://api.github.com/api/users
target: 'https://api.github.com',
//http://localhost:8080/api/users =>https://api.github.com/users
//代理路徑重寫
publicPath: {
'^/api': ''
},
//不能使用 localhost:8080 做爲請求 github 的主機名
changeOrigin: true //以實際代理請求的主機名去請求
}
}
},
//配置開發過程當中的輔助工具
devtool: 'eval',
// 配置對象
module: {
//其餘資源模塊加載規則
rules: [{
//匹配打包過程當中遇到的文件路徑
test: /.css$/,
//匹配文件打包過程當中用的loader 配置了多個loader執行順序是從後往前執行
use: [
'style-loader', //把css-loader轉換後的結果經過style標籤的形式添加到頁面上
'css-loader' //處理css文件的加載器
]
},
{
test: /.png$/,
use: {
loader: 'url-loader', //Data URLs加載器
//配置選項
options: {
limit: 10 * 1024 // 只將10kb如下的文件用url-loader處理
}
}
}, {
test: /.html$/,
use: {
loader: 'html-loader', //html解析器
options: {
// html加載的時候對頁面上的一些屬性作一些額外處理
attrs: [
'img:src', //默認
'a:href'
]
}
}
}, {
test: /.md$/,
use: [
'html-loader',
'./markdown-loader'
]
},
// {
// test: /.js$/,
// use: {
// loader: 'babel-loader', //處理es6代碼當中的新特性
// options: {
// presets: ['@babel/preset-env'] //babel只是一個轉換js代碼的平臺,在平臺轉換過程當中須要額外的插件
// }
// }
// }
]
},
//配置插件
plugins: [
//清理輸出目錄
//new CleanWebpackPlugin(),
//用於拷貝文件到輸出目錄 開發階段最好不要使用這個插件 影響效率
// new CopyWebpackPlugin({
// patterns: [
// // 'public/**',
// 'public'
// ]
// }),
//自動生成index.html
// new HtmlWebpackPlugin({
// title: 'Webpack Plugin Sample',
// meta: {
// viewport: 'width=device-width'
// },
// filename: 'index.html'
// }),
//用於生成about.html
new HtmlWebpackPlugin({
filename: 'index.html'
}),
//自定義插件 刪除生成的js文件當中的註釋
new MyPlugin(),
//熱更新插件
new webpack.HotModuleReplacementPlugin()
]
}
if (env === 'production') {
console.log('生成環境')
config.mode = 'production'
config.devtool = false
config.plugins = [...config.plugins, new CleanWebpackPlugin()]
} else {
console.log('開發環境')
}
return config
}
複製代碼
// 開發環境
yarn webpack
// 生產環境
yarn webpack --env production
複製代碼
//爲代碼注入全局成員
new webpack.DefinePlugin({
//符合JS語法的代碼
API_BASE_URL: '"https://api.example.com"'
})
複製代碼
Tree Shaking不是指某個配置選項,它是一組功能搭配使用後的效果
production模式下自動開啓
其餘模式開啓
//集中配置webpack內部的一些優化功能
optimization: {
//在輸出結果中只導出被外部使用了的成員
usedExports: true,
//開啓代碼壓縮功能
minimize: true
}
複製代碼
webpack將咱們全部的代碼都打包到一塊兒,若是咱們的應用程序很是複雜,模塊很是多的狀況下,那麼咱們的打包結果就會特別的大,咱們的應用程序開始工做時並非每一個模塊在啓動時都是必要的,比較合理的方案是分包,按需加載,這樣就能大大提升咱們應用程序的相應速度和運行效率
多入口打包存在一個小問題,不一樣的打包入口當中必定會存在一些公用的部分
//把全部的公共模塊提取到單獨的bundle當中
splitChunks: {
chunks: 'all'
}
複製代碼
部署前端資源文件時,會開啓靜態資源緩存,對於用戶的瀏覽器而言,它就能夠緩存咱們的靜態資源文件,提升咱們總體應用程序的相應速度
生產模式下,文件名使用Hash,一旦資源文件發生改變,文件名稱也會發生變化
hash:整個項目當中有任何一個地方發生改動,這一次打包過程中的hash值都會發生變化
chunkhash:在打包過程中只要是同一路的打包,chunkhash都是相同的
contenthash:根據輸出文件的內容生成的hash值
能夠經過佔位符的方式指定生成hash的長度,例如:[contenthash:8]
env關鍵字可使用的環境,能夠同時開啓多個環境
browser
- 瀏覽器環境中的全局變量。node
- Node.js 全局變量和 Node.js 做用域。commonjs
- CommonJS 全局變量和 CommonJS 做用域 (用於 Browserify/WebPack 打包的只在瀏覽器中運行的代碼)。shared-node-browser
- Node.js 和 Browser 通用全局變量。es6
- 啓用除了 modules 之外的全部 ECMAScript 6 特性(該選項會自動設置 ecmaVersion
解析器選項爲 6)。worker
- Web Workers 全局變量。amd
- 將 require()
和 define()
定義爲像 amd 同樣的全局變量。mocha
- 添加全部的 Mocha 測試全局變量。jasmine
- 添加全部的 Jasmine 版本 1.3 和 2.0 的測試全局變量。jest
- Jest 全局變量。phantomjs
- PhantomJS 全局變量。protractor
- Protractor 全局變量。qunit
- QUnit 全局變量。jquery
- jQuery 全局變量。prototypejs
- Prototype.js 全局變量。shelljs
- ShellJS 全局變量。meteor
- Meteor 全局變量。mongo
- MongoDB 全局變量。applescript
- AppleScript 全局變量。nashorn
- Java 8 Nashorn 全局變量。serviceworker
- Service Worker 全局變量。atomtest
- Atom 測試全局變量。embertest
- Ember 測試全局變量。webextensions
- WebExtensions 全局變量。greasemonkey
- GreaseMonkey 全局變量。extends
parserOptions
ESLint 容許你指定你想要支持的 JavaScript 語言選項。默認狀況下,ESLint 支持 ECMAScript 5 語法。你能夠覆蓋該設置,以啓用對 ECMAScript 其它版本和 JSX 的支持。
ecmaVersion
- 默認設置爲 3,5(默認), 你可使用 六、七、八、9 或 10 來指定你想要使用的 ECMAScript 版本。你也能夠用使用年份命名的版本號指定爲 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
sourceType
- 設置爲 "script"
(默認) 或 "module"
(若是你的代碼是 ECMAScript 模塊)。
ecmaFeatures
複製代碼
- 這是個對象,表示你想使用的額外的語言特性:
globalReturn
- 容許在全局做用域下使用 return
語句impliedStrict
- 啓用全局 strict mode (若是 ecmaVersion
是 5 或更高)jsx
- 啓用 JSXexperimentalObjectRestSpread
- 啓用實驗性的 object rest/spread properties 支持。(**重要:**這是一個實驗性的功能,在將來可能會有明顯改變。 建議你寫的規則 不要 依賴該功能,除非當它發生改變時你願意承擔維護成本。)rules
globals