webpack的安裝
安裝本地的webpack
yarn add webpack webpack-cli -D
複製程式碼
零配置執行
npx webpack
npx webpack --mode production // 預設為生產環境 會進行壓縮打包
npx webpack --mode development
複製程式碼
webpack_require 相當於是webpack自己實現的一套模組化的機制
手動配置
預設配置檔名稱為 webpack.config.js
module.exports = {
mode: 'development', // 模式 預設兩種 production development
entry: './src/index.js', // 入口
output: {
filename: 'bundle.[hash:8].js', // 出口 [hash:8]顯示8位hash值
path: path.resolve(__dirname, 'build') // path必須是一個絕對路徑 path.resolve幫我們把相對路徑解析成絕對路徑
},
}
複製程式碼
在webpack-cli/bin/config-yargs中可以看到有這樣一行 defaultDescription: "webpack.config.js or webpackfile.js" 即配置檔名稱為webpack.config.js or webpackfile.js 當然我們也可以手動指定配置檔案的名稱
npx webpack --config filename
複製程式碼
也可以通過在package.json中的script裡配置
"scripts":{
"build": "webpack --config webpack.config.js" // webpack.config.js可改為自定義檔名
},
複製程式碼
npm run build
複製程式碼
如果一定要手動傳參也可以通過多加兩個-
"scripts":{
"build": "webpack" // webpack.config.js可改為自定義檔名
},
複製程式碼
npm run build -- --config webpack.config.js
複製程式碼
到目前為止,我們的配置依然很弱,只能打包js檔案,接下來我們繼續新增更多的配置
下面我們希望能夠通過http://localhost 這樣的方式來啟動一個服務, 我們可以通過webpack內建的一個服務 webpack-dev-server (內部是通過express實現的)
yarn add webpack-dev-server -D
複製程式碼
現在我們可以通過
npx webpack-dev-server
複製程式碼
當然也同樣可以通過package.json設定
"scripts": {
"dev": "webpack-dev-server",
"build": "webpack --config webpack.config.js"
},
複製程式碼
然後執行
npm run dev
複製程式碼
同時我們可以給在webpack.config.js中對webpack-dev-server進行配置
devServer: { // 開發伺服器的配置
port: '3000',
progress: true,
contentBase: './build',
open: true
},
複製程式碼
html外掛
期望:動態生成build/index.html, 並把打包後的檔案引入到index.html
在src目錄下建index.html,這時我們需要使用外掛HtmlWebpackPlugin,plugin的用法大都相同,HtmlWebpackPlugin是一個類,new一下就可以了
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html', // template檔案
filename: 'index.html', // 生成的template檔名稱 預設為index.html
hash: true, // 在生成的html中新增引用hash
minify: {
removeAttributeQuotes: true, // 去除雙引號
collapseWhitespace: true, // 去除空行
}
}),
],
複製程式碼
到這裡可以看到我們既可以通過在配置output的時候通過filename: bundle.[hash:8].js 來給生成檔案新增hash,也可以通過HtmlWebpackPlugin的配置hash來實現,兩者新增hash的方式分別為 bundle.12345678.js和 bundle?12345678
而通過filename: bundle.[hash:8].js這種方式實現,我們還需要再做一步,就是在每次重新打包的時候把舊的檔案刪除 // todo
樣式處理
我們知道,webpack預設只支援js模組,那麼我們怎麼處理css/less/scss等模組呢?這時候就需要loader上場了
You may need an appropriate loader to handle this file type.
複製程式碼
module: { // 模組
rules: [ // 規則
// css-loader 主要用來解析@import這種語法
// style-loader 把樣式插入頁面
// loader特點,功能單一 多個loader可以協作
// 一個loader可以使用字串,多個可以使用陣列, 需要傳入引數時可以使用物件方式
// loader的順序,預設為從右向左, 從下到上執行 webpack選擇了compose方式
// {
// test: '/\.css$/', use: [
// { loader: 'css-loader', options: {} } // 物件方式
// ]
// },
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
]
},
複製程式碼
less、sass檔案同理, 以scss檔案為例:
{
test: /\.css$/, use: [
{ loader: 'style-loader', options: { insertAt: 'top' } }, // 物件方式 insertAt插入位置
{ loader: 'css-loader', options: {} },
]
},
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
複製程式碼
css抽離
webpack4中,css抽離需要外掛 mini-css-extract-plugin (注意不再是extract-text-webpack-plugin)
new miniCssExtractPlugin({
filename: 'main.css', // 抽離出的css的檔名
}),
複製程式碼
同時在module.rules中做如下修改以避免重複插入:
- // { test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
+ { test: /\.scss$/, use: [miniCssExtractPlugin.loader, 'css-loader', 'sass-loader'] },
複製程式碼
自動新增字首
我們可以使用postcss-loader autoprefixer來實現
- // { test: /\.scss$/, use: [miniCssExtractPlugin.loader, 'css-loader', 'sass-loader'] },
+ { test: /\.scss$/, use: [miniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'] },
複製程式碼
在根目錄下新建postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'), // 自動新增字首
]
}
複製程式碼
壓縮
此時我們設定mode為production,發現js和html都已經是壓縮過的了,可是css檔案卻沒有。我們這裡引入另外一個外掛:optimize-css-assets-webpack-plugin來優化css資源
let OptimizeCss = require('optimize-css-assets-webpack-plugin');
plugins: [
...,
new OptimizeCss(),
]
複製程式碼
當然我們也可以通過uglifyjs-webpack-plugin來壓縮我們的js檔案
let UglifyjsPlugin = require('uglifyjs-webpack-plugin');
plugins: [
...,
new UglifyjsPlugin(),
]
複製程式碼
es6
我們希望打包後的檔案可以把es6語法轉為es5,可以通過babel-loader幫我們實現
// src/a.js
console.log('this is a');
const fn = () => {
console.log('fn');
}
複製程式碼
安裝babel依賴模組
yarn add babel-loader @babel/core @babel/preset-env -D
複製程式碼
{
test: /\.js|jsx$/, use:
{
loader: 'babel-loader', options: {
presets: ['@babel/preset-env']
}
}
},
複製程式碼
es7
現在寫es6的語法沒有問題了,但是我們有可能用到es7的語法, 比如類的寫法,這時候我們還需要藉助一個外掛:@babel/plugin-proposal-class-properties 又比如裝飾器的寫法,我們可以藉助@babel/plugin-proposal-decorators來實現
{
test: /\.js|jsx$/, use:
{
loader: 'babel-loader', options: {
presets: ['@babel/preset-env'],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }], // 支援es7的裝飾器的寫法 要放在前面
'@babel/plugin-proposal-class-properties', // 支援es7的類的寫法
]
}
}
},
複製程式碼
這裡需要注意的是@babel/plugin-proposal-decorators要放在@babel/plugin-proposal-class-properties前面。
es6新的API
babel只會幫我們把es6新的語法轉成es5,但是對於新的API如:promise, generater 等我們還需要藉助一個包 @babel-polyfill(但是比較大) 同時我們可以藉助一個外掛--@babel/plugin-transform-runtime 做了一定優化,如程式碼抽離
js語法校驗 eslint
yarn add eslint eslint-loader
複製程式碼
{
test: /\.js|jsx$/,
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre', // pre post
}
}
},
複製程式碼
接下來就可以使用自己配置好的.eslintrc.json檔案(放在根目錄下),當然我們也可以到eslint官網,手動進行配置,然後下載eslintrc.json,只要加個.就行了。
全域性變數的引入
- 簡單粗暴
import $ from 'jquery';
console.log($)
console.log(window.$) // undefined
複製程式碼
- 內聯loader expose-loader 暴露到全域性的loader,用法如下:
import $ from 'expose-loader?$!jquery';
console.log($)
console.log(window.$) // undefined
複製程式碼
- webpack expose-loader 只能通過window訪問
{
test: require.resolve('jquery'),
use: 'expose-loader?$'
},
// index.js
console.log(window.$)
複製程式碼
- webpack內建外掛
let webpack = require('webpack');
new webpack.ProvidePlugin({ // 在每個模組中都注入$
$: 'jquery',
}),
// index.js
console.log($); // 都可以訪問
console.log(window.$)
複製程式碼
- cdn引入+webpack
externals: { // 外部引入,不需要打包
jquery: '$',
},
// index.js
import $ from 'jquery'; // 雖然引入但是不會再打包
console.log($);
複製程式碼
圖片處理
我們使用圖片的場景有兩種:
- 在js中建立圖片來引用
- 再css中使用,background
- img標籤的使用
// index.js
let img = new Image();
img.src = require('./logo.png');
document.body.appendChild(img);
複製程式碼
這時我們需要藉助 file-loader 了
{
test: /\.png|jpg|gif|jpeg$/,
loader: 'file-loader',
options: {
}
},
複製程式碼
// index.js
import logo from './logo.png'; // 返回一個新的檔案 好處是可以重新命名圖片
let img = new Image();
img.src = logo;
document.body.appendChild(img);
// a.css
body{
color: yellow;
background: url('./logo.png') no-repeat;
}
複製程式碼
ok,發現前兩種都沒有什麼問題,可是第三種直接寫在html中的卻不行
<body>
<img src='./logo.png' alt=""/>
<!-- 模版 -->
</body>
複製程式碼
處理直接寫在html裡的圖片,還需要用到另一個loader:
{
test: /\.html/,
use: 'html-withimg-loader'
},
複製程式碼
重新啟動就好了。
檔案打包分類
如果想要做更多的限制呢,比如說對打包圖片大小的限制打包成base64以減少http請求(base64會比原始檔大1/3左右),我們可以使用 url-loader
{
test: /\.png|jpg|gif|jpeg$/,
loader: 'url-loader',
options: {
limit: 4 * 1024, // 圖片大小限制值
outputPath: '/img/', // 輸出目錄
publicPath: 'http://58.com' // 新增打包後的圖片域名
}
},
複製程式碼
打包多頁面應用
基本配置如下:
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
home: './src/index.js',
other: './src/other.js',
},
output: {
filename: '[name].js', // name為變數,根據entry的命名生成對應打包後的檔名稱
path: path.resolve(__dirname, 'dist'),
},
plugins: [
new HtmlWebpackPlugin({ // 這裡需要new多個HtmlWebpackPlugin
template: './src/index.html',
filename: 'home.html',
chunks: ['home'] // html依賴,決定了打包後的哪些檔案插入該模版中, 可以寫多個,且有順序
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'other.html',
chunks: ['other', 'home']
}),
],
}
複製程式碼
配置source-map
// devtool: 'source-map', // 增加對映檔案 會單獨生成一個sourcemap檔案,出錯了會標示當前出錯的列和行 特點 大 全
devtool: 'eval-map',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'home.html',
}),
],
複製程式碼
watch用法
output: {
filename: '[name].js', // name為變數,根據entry的命名生成對應打包後的檔名稱
path: path.resolve(__dirname, 'dist'),
},
watch: true, // 實時編譯打包
watchOptions: { // 監控選項
poll: 1000, // 每秒訪問多少次
aggregateTimeout: 500, // 防抖
ignored: /node_modules/
},
複製程式碼
外掛使用
- CleanWebpackPlugin 每次打包刪除dist
- CopyWebpackPlugin // copy檔案目錄
- BannerPlugin // 給打包後的檔案新增頭註釋
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'home.html',
}),
new CleanWebpackPlugin('./dist'), // 傳入要刪除的目錄 也可傳陣列
new CopyWebpackPlugin([{ from: './src/static', to: './dist' }]), //需要拷貝的目錄 必須是arr
new webpack.BannerPlugin('make 2019 by beth.miao'),
],
複製程式碼
webpack跨域問題 配置代理 proxy
proxy: {
'/api': {
target: 'http://localhost:3001',
pathRewrite: { '/api': '' }
}
}
複製程式碼
resolve 屬性的配置
resolve: { // 解析第三方包 common
modules: [path.resolve('node_modules')],
// mainFields: ['style', 'main'],
// mainFiles: '',
alias: {
bootstrap: 'bootstrap/dist/css/bootstrap.css',
},
extensions: ['.js', '.css', '.json', 'vue'], // 引入路徑字尾名處理
},
複製程式碼