webpack4入門篇

一.安裝步驟

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環境中正則表達式

二.部署webpack

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"
  }
}
複製代碼

三.配置流程

1.Html在webpack中的配置

新建webpack.config.js文件 新建index.html文件vue-cli

必須都在根目錄下面 webpack默認找根目錄下的配置

配置咱們的入口entry,在vue-cli裏至關於跟目錄下的main.js,咱們的出口output。咱們能夠把webpack理解爲一個工廠,進入至關於把各類各樣的原料放進咱們的工廠了,而後工廠進行一系列的打包操做把打包好的東西,向外輸出,而後就能夠去出售了(上線)。

html-webpack-plugin

插件來將 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}: 指定具體的排序規則
})
複製代碼

2.css在webpack中的配置

咱們但願使用 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',
    })
  ]
}
複製代碼

3.圖片資源在webpack中的配置

npm install file-loader url-loader -D

file-loader: 能夠用於處理不少類型的文件,它的主要做用是直接輸出文件,把構建後的文件路徑返回。

url-loader: 若是圖片較多,會發不少 http 請求,會下降頁面性能。url-loader 會將引入的圖片編碼,生成 dataURl。至關於把圖片數據翻譯成一串字符。再把這串字符打包到文件中,最終只須要引入這個文件就能訪問圖片了。固然,若是圖片較大,編碼會消耗性能。所以 url-loader 提供了一個 limit 參數,小於 limit 字節的文件會被轉爲 DataURl,大於 limit 的還會使用 file-loader 進行 copy。

  • url-loader 能夠看做是加強版的 file-loader。
  • url-loader 把圖片編碼成 base64 格式寫進頁面,從而減小服務器請求。

配置以下:

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]",
            }
          }
        ]
      }
    ]
  }
  //...
}
複製代碼

4.js在webpack中的配置

如今隨着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

四:打包前清理源目錄文件 clean-webpack-plugin

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

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 的解析,配置別名

若是咱們能夠精簡 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']
  }
}
複製代碼

八:webpack-dev-serve

安裝: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' : ''}
      }
    },
  },
複製代碼

九:模塊熱替換(hot module replacement)

模塊熱替換(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,這裏就不作展開了

十:完整webpack代碼

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': ''}
      }
    },
  },

};
複製代碼
相關文章
相關標籤/搜索