1.新建項目webpack-democss
2.安裝webpackhtml
npm install webpack webpack-cli -gvue
3.項目初始化node
npm init -y //-y默認全部的配置webpack
安裝依賴環境es6
npm i webpack webpack-cli -Dweb
//-D webpack安裝在devDependencies環境中正則表達式
1.package.json裏配置咱們的scriptsvuex
{
"name": "webpack_demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --mode production"
//咱們在這裏配置,就可使用npm run build 打包咱們的項目 像使用vue-cli腳手架那樣
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8"
}
}
複製代碼
新建webpack.config.js文件 新建index.html文件vue-cli
必須都在根目錄下面 webpack默認找根目錄下的配置
配置咱們的入口entry,在vue-cli裏至關於跟目錄下的main.js,咱們的出口output。咱們能夠把webpack理解爲一個工廠,進入至關於把各類各樣的原料放進咱們的工廠了,而後工廠進行一系列的打包操做把打包好的東西,向外輸出,而後就能夠去出售了(上線)。
插件來將 HTML 引用路徑和咱們的構建結果關聯起來。 npm run buid 以後 dist 目錄就會多個 index.html 並引入了 main.js.
new HtmlWebpackPlugin({
title: 'webpack-demo',//標題
filename: 'index.html', // 配置輸出文件名和路徑
template: './index.html', // 配置要被編譯的html文件
inject: true,//script標籤位於html文件的body底部 true/body/head/false 默認true
favicon: './src/assets/img/logo.png',//指定頁面圖標 而後在生成的html中就有一個link標籤:<link rel='shortcut icon' href='example.ico'>
// 壓縮 => production 模式使用
//生產爲true 其餘的時候爲false
minify: {
caseSensitive:false,//是否大小寫敏感 默認flase
removeAttributeQuotes: true, //去掉屬性引用 刪除雙引號 默認false
collapseWhitespace: true, //是否去除空格 摺疊 html 爲一行 默認false
removeComments:true//去註釋 默認false
},
hash: true,//是否生成hash添加在引入文件地址的末尾,這個能夠避免緩存帶來的麻煩。默認爲false。
cache: true,//默認是true的,表示內容變化的時候生成一個新的文件。
showErrors: true,//是否將錯誤信息寫在頁面裏,默認true,出現錯誤信息則會包裹在一個pre標籤內添加到頁面上。
chunks:'' //引入的模塊,這裏指定的是entry中設置多個js時,在這裏指定引入的js,若是不設置則默認所有引入。
chunksSortMode: '' //這個選項決定了 script 標籤的引用順序。默認有四個選項,'none' | 'auto' | 'dependency' | 'manual' | {Function}
- none: 無序
- auto: 默認值, 按插件內置的排序方式
- dependency: 根據不一樣文件的依賴關係排序(通常用於生產)
- manual: chunks按引入的順序排序, 即屬性chunks的順序
- {Function}: 指定具體的排序規則
})
複製代碼
咱們但願使用 webpack 來進行構建 css 文件,爲此,須要在配置中引入 loader 來解析和處理 CSS 文件:
npm install style-loader css-loader -D
在src的assets裏面的css文件中新增color.css添加樣式,在index.js中引入這個css import './assets/css/color.css'
在webpack.config.js中配置loader
module: {
/**
* test: 匹配特定條件。通常是提供一個正則表達式或正則表達式的數組
* include: 匹配特定條件。通常是提供一個字符串或者字符串數組
* exclude: 排除特定條件
* and: 必須匹配數組中的全部條件
* or: 匹配數組中任何一個條件,
* nor: 必須排除這個條件
*/
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: ['style-loader', 'css-loader']
}
]
}
複製代碼
經由上述兩個 loader 的處理後,CSS 代碼會轉變爲 JS, 若是須要單獨把 CSS 文件分離出來,咱們須要使用 mini-css-extract-plugin 插件
抽取 css 到獨立文件, 自動添加前綴
npm i mini-css-extract-plugin postcss-loader autoprefixer -D
咱們在寫 css 時難免要考慮到瀏覽器兼容問題,如 transform 屬性,須要添加瀏覽器前綴以適配其餘瀏覽器。故使用到 postcss-loader 這個 loader, 下面則是相關的配置
注意: 若是瀏覽器前綴添加不成功,記得要在autoprefixer後面加("last 100 versions")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
// ...
module: {
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',//爲了防止css裏面有引用背景圖片 圖片打包以後在dist/images路徑錯誤問題
hmr: devMode, // 僅dev環境啓用HMR功能
}
},
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')("last 100 versions")]
}
}
]
}
]
},
plugins: [
//...
new MiniCssExtractPlugin({
// 這裏的配置和webpackOptions.output中的配置類似
// 便可以經過在名字前加路徑,來決定打包後的文件存在的路徑
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
})
]
}
複製代碼
npm install file-loader url-loader -D
file-loader: 能夠用於處理不少類型的文件,它的主要做用是直接輸出文件,把構建後的文件路徑返回。
url-loader: 若是圖片較多,會發不少 http 請求,會下降頁面性能。url-loader 會將引入的圖片編碼,生成 dataURl。至關於把圖片數據翻譯成一串字符。再把這串字符打包到文件中,最終只須要引入這個文件就能訪問圖片了。固然,若是圖片較大,編碼會消耗性能。所以 url-loader 提供了一個 limit 參數,小於 limit 字節的文件會被轉爲 DataURl,大於 limit 的還會使用 file-loader 進行 copy。
配置以下:
module.exports = {
module: {
rules: [
// ...
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
outputPath: 'images/', //輸出到images文件夾
limit: 10000, //是把小於6000B的文件打成Base64的格式,寫入JS
name: "[name]-[hash:5].min.[ext]",
}
}
]
}
]
}
//...
}
複製代碼
如今隨着es6的普及,愈來愈多的代碼使用es6了,可是不少瀏覽器並不支持es6,好比async/awiat,const。所以須要咱們引用babe來把咱們es6的代碼編譯爲es5。在跟目錄下新建.babelrc,簡單配置下
{"presets": ["env"]}
安裝所需依賴:npm i babel-loader babel-core babel-preset-env -D
{
test: /\.js$/, //es6 => es5
exclude: /node_modules/,
use: 'babel-loader'
}
複製代碼
報錯:Error: Cannot find module '@babel/core' babel-loader@8 requires Babel 7.x (the package '@babel/core'). If you'd like to use Babel 6.x ('babel-core'), you should install 'babel-loader@7' 由於babel-loader的版本問題
先卸載 npm uninstall babel-loader 重裝一個@7的版本 npm i babel-loader@7 -D
npm install clean-webpack-plugin -D
配置以下:
const CleanWebpackPlugin = require('clean-webpack-plugin')
module.exports = {
plugins: [
new CleanWebpackPlugin(['dist'])
]
}
複製代碼
報錯:TypeError: CleanWebpackPlugin is not a constructor 修改引用方式:const {CleanWebpackPlugin} = require('clean-webpack-plugin');
又報錯:Error: clean-webpack-plugin only accepts an options object 修改調用方式,不傳入目錄:new CleanWebpackPlugin()
假如你 a.js 和 b.js 都 import 了 c.js 文件,這段代碼就冗雜了。爲何要提取公共代碼,簡單來講,就是減小代碼冗餘,提升加載速度。
module.exports = {
//...
optimization: {
splitChunks: {
cacheGroups: {
commons: {
// 抽離本身寫的公共代碼
chunks: 'initial',
name: 'common', // 打包後的文件名,任意命名
minChunks: 2, //最小引用2次
minSize: 0 // 只要超出0字節就生成一個新包
},
styles: {
name: 'styles', // 抽離公用樣式
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vendor: {
// 抽離第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包後的文件名,任意命名
// 設置優先級,防止和自定義的公共代碼提取時被覆蓋,不進行打包
priority: 10
}
}
}
}
}
複製代碼
hash 是幹嗎用的? 咱們每次打包出來的結果可能都是同一個文件,那我上線的時候是否是要替換掉上線的 js,那我怎麼知道哪是最新的呢,咱們通常會清一下緩存。而 hash 就是爲了解決這個問題而存在的
module.exports = {
//...
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js'
},
//...
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
})
]
}
複製代碼
若是咱們能夠精簡 resolve 配置,讓 webpack 在查詢模塊路徑時儘量快速地定位到須要的模塊,不作額外的查詢工做,那麼 webpack 的構建速度也會快一些
module.exports = {
resolve: {
/**
* alias: 別名的配置
*
* extensions: 自動解析肯定的擴展,
* 好比 import 'xxx/theme.css' 能夠在extensions 中添加 '.css', 引入方式則爲 import 'xxx/theme'
* @default ['.wasm', '.mjs', '.js', '.json']
*
* modules 告訴 webpack 解析模塊時應該搜索的目錄
* 若是你想要添加一個目錄到模塊搜索目錄,此目錄優先於 node_modules/ 搜索
* 這樣配置在某種程度上能夠簡化模塊的查找,提高構建速度 @default node_modules 優先
*/
extensions: ['.vue', '.js', '.json','.css'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@':
path.resolve(__dirname, 'src'),
'@components':
path.resolve(__dirname, 'src/components/'),
'@assets':
path.resolve(__dirname, 'src/assets'),
},
modules: [path.resolve(__dirname, 'src'), 'node_modules']
}
}
複製代碼
安裝:npm install webpack-dev-server -D package.json 中 scripts 中添加:"dev": "webpack-dev-server --mode development"
devServer: {
host: '0.0.0.0',//主機名
port: 8080,//端口
open: true,//自動打開瀏覽器
compress: true,//服務器壓縮
hot:true,//熱更新
inline:true,//頁面自動刷新
//跨域問題
proxy:{
'/api': {
target: 'https://testbi.promni.cn/v2/api',
secure: false,
changeOrigin: true,
pathRewrite: {'^/api' : ''}
}
},
},
複製代碼
模塊熱替換(HMR - Hot Module Replacement)功能會在應用程序運行過程當中替換、添加或刪除模塊,而無需從新加載整個頁面。主要是經過如下幾種方式,來顯著加快開發速度:
保留在徹底從新加載頁面時丟失的應用程序狀態。 只更新變動內容,以節省寶貴的開發時間。 調整樣式更加快速 - 幾乎至關於在瀏覽器調試器中更改樣式。
上面咱們 npm start 後修改一次文件,頁面就會刷新一次。這樣就存在很大問題了,好比咱們使用 redux, vuex 等插件,頁面一刷新那麼存放在 redux, vuex 中的東西就會丟失,很是不利於咱們的開發。
import webpack from 'webpack';
plugins: [
new webpack.HotModuleReplacementPlugin()
//...
]
配置後還不行,由於 webpack 還不知道你要更新哪裏, 修改 src/index.js 文件, 添加
if (module.hot) {
module.hot.accept()
}
複製代碼
可是可是有個問題是,你修改 css/less 等樣式文件並未發生改變, what ? HMR 修改樣式表 須要藉助於 style-loader, 而咱們以前用的是 MiniCssExtractPlugin.loader, 這也好辦,修改其中一個 rules 就能夠了,咱們能夠試試改
module.exports = {
module: {
rules: [
{
test: /\.less$/,
use: [
// MiniCssExtractPlugin.loader,
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')] // 添加css中的瀏覽器前綴
}
},
'less-loader'
]
}
]
}
}
複製代碼
咱們能夠發現,dev 下配置的 loader 爲 style-loader , 而生產環境下則是須要 MiniCssExtractPlugin.loader 這就涉及到了不一樣環境之間的配置。能夠經過 process.env.NODE_ENV 獲取當前是開發環境或者是生產環境,而後配置不一樣的 loader,這裏就不作展開了
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
//打包入口
entry: {
main: './src/index.js',
page1: "./src/assets/js/page1.js",//測試提取公用代碼
page2: "./src/assets/js/page2.js",//測試提取公用代碼
},
//打包出口
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[hash:8].js'
},
module: {
/**
* test: 匹配特定條件。通常是提供一個正則表達式或正則表達式的數組
* include: 匹配特定條件。通常是提供一個字符串或者字符串數組
* exclude: 排除特定條件
* and: 必須匹配數組中的全部條件
* or: 匹配數組中任何一個條件,
* nor: 必須排除這個條件
*/
rules: [
{
test: /\.css$/,
include: [path.resolve(__dirname, 'src')],
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../',//爲了防止css裏面有引用背景圖片 圖片打包以後在dist/images路徑錯誤問題
hmr: devMode, // 僅dev環境啓用HMR功能
}
},
// 'style-loader', 模塊熱替換時候用的
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')("last 100 versions")]//添加瀏覽器前綴
}
}
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
outputPath: 'images/', //輸出到images文件夾
limit: 6000, //是把小於6000B的文件打成Base64的格式,寫入JS
name: "[name]-[hash:5].min.[ext]",
}
}
]
},
{
test: /\.js$/, //es6 => es5
exclude: /node_modules/,
use: 'babel-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack-demo',//標題
filename: 'index.html', // 配置輸出文件名和路徑
template: './index.html', // 配置要被編譯的html文件
favicon: './src/assets/img/logo.png',//指定頁面圖標 而後在生成的html中就有一個link標籤:<link rel='shortcut icon' href='example.ico'>
// 壓縮 => production 模式使用
minify: {
removeAttributeQuotes: true, //去掉屬性引用 刪除雙引號
collapseWhitespace: true, //是否去除空格 摺疊 html 爲一行
removeComments: true//去註釋
},
hash: true,//是否生成hash添加在引入文件地址的末尾,這個能夠避免緩存帶來的麻煩。默認爲true。
}),
new MiniCssExtractPlugin({
// 這裏的配置和webpackOptions.output中的配置類似
// 便可以經過在名字前加路徑,來決定打包後的文件存在的路徑
filename: devMode ? 'css/[name].css' : 'css/[name].[hash].css',
chunkFilename: devMode ? 'css/[id].css' : 'css/[id].[hash].css',
}),
//清理源目錄文件
new CleanWebpackPlugin(),
//模塊熱替換
new webpack.HotModuleReplacementPlugin()
],
optimization: {
//壓縮文件 mode:production 生產環境配置
minimizer: [
new OptimizeCssAssetsWebpackPlugin(),// 壓縮css
new UglifyJsPlugin()//壓縮js
],
//提取公用代碼
splitChunks: {
cacheGroups: {
commons: {
// 抽離本身寫的公共代碼
chunks: 'initial',
name: 'common', // 打包後的文件名,任意命名
minChunks: 2, //最小引用2次
minSize: 0 // 只要超出0字節就生成一個新包
},
styles: {
name: 'styles', // 抽離公用樣式
test: /\.css$/,
chunks: 'all',
minChunks: 2,
enforce: true
},
vendor: {
// 抽離第三方插件
test: /node_modules/, // 指定是node_modules下的第三方包
chunks: 'initial',
name: 'vendor', // 打包後的文件名,任意命名
// 設置優先級,防止和自定義的公共代碼提取時被覆蓋,不進行打包
priority: 10
}
}
}
},
// 減小 resolve 的解析,配置別名
resolve: {
extensions: ['.vue', '.js', '.json', '.css'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@':
path.resolve(__dirname, 'src'),
'@components':
path.resolve(__dirname, 'src/components/'),
'@assets':
path.resolve(__dirname, 'src/assets'),
},
},
//webpack-dev-server mode:development 開發環境配置
devServer: {
host: '0.0.0.0',//主機名
port: 8080,//端口
open: true,//自動打開瀏覽器
compress: true,//服務器壓縮
hot: true,//熱更新
inline: true,//頁面自動刷新
//跨域問題
proxy: {
'/api': {
target: 'https://testbi.promni.cn/v2/api',
secure: false,
changeOrigin: true,
pathRewrite: {'^/api': ''}
}
},
},
};
複製代碼