webpack
認識webpack
webpack : 模塊打包機;分析項目結構,找到相對應的模塊,並且找出一些瀏覽器不能直接識別的拓展性的比如less、typeScript等編譯成瀏覽器識別的文件;
es6 let a = 10; IE10不能識別es6;
less
import export
webpack會把es6編譯成es5,把less編譯成css;把ts編譯成js;
打包: 會把js進行編譯和壓縮,甚至把大量的js文件壓縮到一個js文件中,把圖片編譯成base64格式等等,當客戶端訪問這個項目時,不需要再發送那麼多次請求,壓縮了資源的大小;
瀏覽器只識別html,css,js
Webpack詳解
webpack是一個現代 JavaScript 應用程序的 靜態模塊打包器(module bundler)。當 webpack 處理應用程序時,它會遞歸地構建一個依賴關係圖(dependency graph),其中包含應用程序需要的每個模塊,然後將所有這些模塊打包成一個或多個bundle。webpack 本身是基於 node.js 開發的。
從 webpack v4.0.0 版本開始,可以不用引入一個配置文件(零配置文件),然而 webpack 仍然還是高度可配置的。
1. 安裝webpack
目前 _@vue/cli _和 _create-react-app _基本上採用的是 _webpack 4.0 _以上版本,所以以第四代版本爲主;第四代版本需要我們安裝 _webpack _和 webpack-cli(可執行命令);
爲了防止全局安裝 _webpack _的版本衝突,我們真實項目開發的時候基本上以安裝在本地項目中爲主;
$ npm init -y
$ npm install webpack webpack-cli --save-dev
OR
$ yarn add webpack webpack-cli -D
2.webpack的基礎使用
- 初步體驗(零配置)
/*
* 默認會打包SRC目錄中的JS文件(入口默認index.js)
* 打包完成的目錄默認是DIST/MAIN.JS
*
* npx:http://www.ruanyifeng.com/blog/2019/02/npx.html
* 默認執行node_modules/bin/webpack.cmd文件
* webpack默認支持CommonJS和ES6 Module的模塊規範,依此進行依賴打包
*/
$ npx webpack
- 自定義基礎配置
- webpack.config.js OR webpackfile.js
let path = require('path');
module.exports = {
// 打包模式,開發環境 development 生產環境 production
mode: 'production',
// 入口
entry: './src/index.js',
// 輸出
output: {
// 輸出文件的文件名
filename: 'bundle.js',
// 輸出目錄的"絕對路徑"
path: path.resolve(__dirname, 'dist')
}
}
- 自定義配置文件名
- $ npx webpack --config webpack.config.development.js
- 可在package.json中配置可執行的腳本命令(區分開發環境)
"scripts": {
"serve": "webpack --config webpack.config.development.js",
"build": "webpack --config webpack.config.production.js"
},
3.webpack-dev-server
https://webpack.js.org/configuration/dev-server/
- 安裝:$ yarn add webpack-dev-server -D
- 基礎配置
/* webpack.config.js */
// 配置DEV-SERVER
devServer: {
// 端口
port: 3000,
// 顯示編譯進度
progress: true,
// 指定訪問資源目錄
contentBase: './dist',
// 自動打開瀏覽器
open: true
}
/* package.json */
"scripts": {
"serve": "webpack-dev-server",
"build": "webpack"
}
- $ npm run serve
- $ npx webpack-dev-server
- 代碼更改後,會自動重新編譯,然後自動刷新頁面
4.html-webpack-plugin
https://www.webpackjs.com/plugins/html-webpack-plugin/
- 安裝:$ yarn add html-webpack-plugin -D
- 在webpack.config.js中使用
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...,
// 在 webpack 中使用插件
plugins: [
new HtmlWebpackPlugin({
// 指定自己的模板
template: './src/index.html',
// 輸出的文件名
filename: 'index.html',
// 給引入的文件設置 HASH 戳(清除緩存的),也可以在 output 中設置 filename: 'bundle.[hash]
// .js' 來生成不同的文件
hash: true,
// 控制是否以及以何種方式最小化輸出
// https://github.com/kangax/html-minifier
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true,
removeEmptyAttributes: true
}
})
]
}
5.webpack中的加載器loader:處理樣式的
- 安裝:$ yarn add css-loader style-loader less less-loader autoprefixer postcss-loader … -D
module.exports = {
// 配置模塊加載器 LOADER
module: {
// 模塊規則:使用加載器(默認從右向左執行,從下向上)
rules: [{
test: /\.(css|less)$/, // 基於正則表達式匹配哪些模塊需要處理
use: [
"style-loader", // 把 CSS 插入到 HEAD 中
"css-loader", // 編譯解析 @import/URL() 這種語法
"postcss-loader", // 設置前綴
{
loader: "less-loader",
options: {
// 加載器額外的配置
}
}
]
}]
}
}
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
};
package.json
"browserslist": [
"> 1%",
"last 2 versions"
]
6.mini-css-extract-plugin 抽離CSS內容
https://www.npmjs.com/package/mini-css-extract-plugin
- 安裝 $ yarn add mini-css-extract-plugin optimize-css-assets-webpack-plugin uglifyjs-webpack-plugin -D
let MiniCssExtractPlugin = require('mini-css-extract-plugin'),
OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'),
UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
// 設置優化項
optimization: {
// 設置壓縮方式
minimizer: [
// 壓縮 CSS(但是必須指定 JS 的壓縮方式)
new OptimizeCssAssetsWebpackPlugin(),
// 壓縮JS
new UglifyjsWebpackPlugin({
cache: true, // 是否使用緩存
parallel: true, // 是否是併發編譯
sourceMap: true, // 啓動源碼映射(方便調試)
})
]
},
plugins: [
// 使用插件
new MiniCssExtractPlugin({
// 設置編譯後的文件名字
filename: 'main.css'
})
],
module: {
rules: [{
test: /\.(css|less)$/,
use: [
// "style-loader",
// 使用插件中的 LOADER 代替 STYLE 方式
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader"
]
}]
}
}
上述JS壓縮對於 require / import 等還存在問題,需要對於 ES6 中的一些語法進行處理!
7.基於babel實現ES6的轉換和ESLint語法檢測
https://babeljs.io/
https://eslint.org/
- 安裝 $ yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-transform-runtime -D
- 安裝 $ yarn add @babel/runtime @babel/polyfill
- 安裝 $ yarn add eslint eslint-loader -D
module.exports = {
...,
module: {
rules: [...,{
test: /\.js$/,
use: [{
loader: 'babel-loader',
options: {
// 轉換的語法預設(ES6->ES5)
presets: [
"@babel/preset-env"
],
// 基於插件處理 ES6 / ES7 中 CLASS 的特殊語法
plugins: [
["@babel/plugin-proposal-decorators", {
"legacy": true
}],
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
"@babel/plugin-transform-runtime"
]
}
}], // "eslint-loader"
// 設置編譯時忽略的文件和指定編譯目錄
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}]
}
}
參考 https://eslint.org/demo 生成 .eslintrc.json
補充知識:在 vscode 中開啓 ES7 中類的裝飾器,項目根目錄中設置 jsconfig.json
{
"compilerOptions": {
"experimentalDecorators": true
}
}
@log
class A{
a=1;
}
8.暴露全局loader
- $ yarn add expose-loader -D
- 前置加載器、後置加載器、普通加載器…
// 內聯加載器
import jquery from 'expose-loader?$!jquery';
console.log(window.$);
{
// 只要引入 JQUERY 就在全局注入$
test: require.resolve('jquery'),
use: ['expose-loader?$']
}
let webpack = require('webpack');
module.exports = {
plugins: [
// 在每個模塊中都注入$
new webpack.ProvidePlugin({
'$': 'jquery'
})
],
}
// 頁面中
console.log($);
9.webpack中圖片的處理和分目錄分發
- 在JS中創建IMG
- 在CSS中設置背景圖
- 在HTML中寫死
- …
安裝 $ yarn add file-loader url-loader html-withimg-loader -D
module.exports = {
...,
module: {
// 模塊規則:使用加載器(默認從右向左執行)
rules: [..., {
test: /\.(png|jpg|gif)$/i,
use: [{
// 把指定大小內的圖片BASE64
loader: 'url-loader',
options: {
limit: 200 * 1024,
outputPath:'/images'
}
}],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}, {
test: /\.html$/,
use: ['html-withimg-loader']
}]
}
}
最後實現文件分目錄發佈
module.exports = {
output: {
// 配置引用前綴(所有資源前加這個地址)
publicPath: './'
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/main.css'
})
],
module: {
// 模塊規則:使用加載器(默認從右向左執行)
rules: [...,{
test: /\.(png|jpg|gif)$/i,
use: [{
options: {
outputPath: 'images'
}
}]
}]
}
}
實例
命令
- npm run server :“server”: “webpack-dev-server --open”
- npm run build : “build”: “webpack”
結構
webpack.config.js
// webpack 是基於node運行的;這個文件最終要運行在node環境下;
// 入口和出口文件
// 在真實項目開發中,我們常常使用Es6進行開發,當上線之前,把es6編譯成es5;
let path = require("path");
let WebpackHtmlPlugin = require("html-webpack-plugin");
module.exports = {
// __dirname: 當前simple文件夾的絕對路徑
mode: "development",// 開發模式(不壓縮) production :生產環境(壓縮的)默認是壓縮的;
devtool: 'eval-source-map',// 用於瀏覽器的調試
entry: __dirname + "/app/main.js",//webpack打包的入口
output: {
path: __dirname + "/public",// 打包之後的文件存放路徑
filename: "bundle.js"// 打包之後的js的文件名
},
// 多入口多出口的配置方式
// entry:{
// main:__dirname+"/app/main.js",
// greeter:__dirname+"/app/greeter.js"
// },
// output:{
// path:__dirname+"/public",
// filename:'[name].js'
// },
//"/api/getuser"
// 配置dev-server的選項
devServer: {
contentBase: "./public",// 啓動服務的根目錄
inline: true,// 實時刷新
port: 8080,// 讓當前項目在8080端口下啓動
proxy: {// 代理;用於跨域的參數配置
"/api": {// 如果接口中函數api,那麼這個接口就要跨域;
// target : 將要跨域請求的服務器地址;
target: "http://localhost:9000",
secure: false,// 目標服務器是否是安全協議
changeOrigin: false,// 是否修改請求的源頭
}
}
},
/*
test:一個用以匹配loaders所處理文件的拓展名的正則表達式(必須)
loader:loader的名稱(必須)
include/exclude:手動添加必須處理的文件(文件夾)或屏蔽不需要處理的文件(文件夾)(可選);
query:爲loaders提供額外的設置選項(可選)
*/
module: {
rules: [
{
test: /(\.jsx|\.js)$/,// 用正則匹配文件的後綴名,匹配到文件要用loader處理;
use: ["babel-loader"],// 要使用的loader
exclude: "/node_modules/"// 這個文件夾下的js文件不需要使用loader處理;
也可以不加引號用正則匹配/node_modules/
}, {
test: /\.css$/,
// style-loader :會默認生成一個style標籤,將css樣式插入到這個style中;
// 順序必須是先style-loader,再用css-loader
// postcss-loader : 可以給瀏覽器對應的樣式自動加前綴
use: ["style-loader", "css-loader", "postcss-loader"],
// include: /css/
//path(路徑) path.resolve() 方法將路徑或路徑片段的序列解析爲絕對路徑。
//include:[path.resolve(__dirname,"css")]
},
// 1.base64有點: 較少了http請求,加快了頁面的加載時間;避免了圖片的跨域,
不會造成圖片緩存的問題;
// 2.缺點:數據量比較大,可讀性不好,Ie8以下不可用;
// 如果圖片的大小超過了url的limit限制,默認就會調用file-loader去處理該圖片,
此時會生成一個新的圖片而不是轉base64的編碼了;
{
test: /(\.png|\.jpg|.gif)$/,
use: {
loader: "url-loader",
options: {
// 是限制的意思
limit: 8192
}
}
},
{
test: /\.less$/,
// 1.這個順序不能顛倒 ,webpack會從後往前依次進行解析;
先用less-loader把less文件解析成css,將css注入到js文件中,
style-loader創建style標籤,把js中的css放進去;
use: ["style-loader", "css-loader", "less-loader"]
}
]
},
// plugins:這是一個數組
plugins: [
new WebpackHtmlPlugin({
template: __dirname + "/index.html"
})
]
}
// vue-cli
package.json
{
"name": "simple",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-cli --entry ./app/main.js --output ./public/bundle.js",
"build": "webpack",
"server": "webpack-dev-server --open"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.6.1",
"babel-core": "^6.26.3",
"babel-loader": "^7.1.5",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"css-loader": "^3.2.0",
"file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"postcss-loader": "^3.0.0",
"style-loader": "^1.0.0",
"url-loader": "^3.0.0",
"webpack": "^4.39.3",
"webpack-cli": "^3.3.8",
"webpack-dev-server": "^3.8.0"
}
}
postcss.config.js
後綴自動添加
// postcss.config.js
module.exports = {
plugins:[
require("autoprefixer")({
overrideBrowserslist:[
"defaults",
"Android 4.1",
"iOS 7.1",
"Chrome>31",
"ff>31",
"ie>=8",
"last 2 versions",
">0%"
]
})
]
}
.babelrc
把babel的配置選項放在一個單獨的名爲 ".babelrc" 的配置文件中
//.babelrc
{
"presets": [
"react",
"env"
]
}
app/main.js
//main.js
// const greeter = require('./Greeter.js');
// document.querySelector("#root").appendChild(greeter());
// ES6的寫法
// import "../css/index.css";
import "../css/2.less";
import img from "../images/16.jpg";
let a = 555;
let b = 755;
console.log(b);
let ff = a => console.log(a);
ff(a)
console.log(img);
let str=`<img src="${img}"></img>`;
let c=document.querySelector("#root");
c.innerHTML = str;
app/Greeter.js
// Greeter.js
// 這是common.js規範:module.exports require
// import export
// webpack會把JS編譯成瀏覽器識別的
module.exports = function() {
var greet = document.createElement('div');
greet.textContent = "Hi great and greetings!";
return greet;
};