webpack 學習筆記

本文主要分為:

  • 環(huán)境配置
  • 使用配置文件
  • CSS 處理
  • ES6 代碼編輯
  • 文件壓縮
  • SASS 處理
  • CSS 與 JS 分離
  • 文件處理 file-loader 與 url-loader
  • 多入口及自動清理

客位看官可直接 ctrl + f 搜索對應關鍵字

環(huán)境配置
  • window + r ,輸入 cmd 打開命令行

  • 新建并進入 webpack-3.10.0 文件夾

    mkdir webpack-3.10.0 && cd webpack-3.10.0
    
  • 使用 sublime text3subl.exe 打開該文件夾

    subl.exe

  • webpack-3.10.0 目錄下初始化操作,生成 package.json 文件

    npm init -y
    

也可以直接使用 npm init 來初始化 package.json 文件,但這樣需要手動填寫項目名之類的東西,加上 -y 表示使用默認配置

npm init -y

  • 新建 src 文件夾,今后將要打包的文件全部放入該文件夾下

    新建 src 文件夾

  • src 下新建 main.js 并隨便敲一點代碼

    main.js

  • 安裝 webpack

    npm install webpack@3.10.0 --save-dev
    

這里是安裝指定版本號的 webpack,不加版本號則是最新版

安裝完成

安裝完成后的 package.json

package.json

安裝完成后的項目目錄


新增了 node_modules 目錄
  • 修改 package.json

    增加執(zhí)行腳本語句

  • 打包

    #  命令語句        源文件        目標文件
    npm run start src/main.js dist/bundle.js
    

如果沒有 dist 目錄則自動新建

打包

  • 打包結果


    打包后
  • webpack-3.10.0 目錄下創(chuàng)建 index.html 文件,引入之前打包好的 bundle.js 文件

<!DOCTYPE html>
<html>
<head>
    <title>webpack-3.10.0</title>
</head>
<body>
    <h1>Hello World!</h1>
    <script type="text/javascript" src="dist/bundle.js"></script>
</body>
</html>
打包并引入成功
  • 我們同樣可以把打包的語句直接寫在 package.json 中,免得每次輸入很麻煩
    "start":"webpack src/main.js dist/bundle.js"
    

image.png

這樣我們在命令行中直接調用 npm run start 也能實現打包的效果

  • 現在有個問題,當我們修改 main.js 文件的內容時,刷新頁面并不會顯示更新的改動,如果想讓頁面同步的話,我們還需再執(zhí)行一次 npm run start 語句,每次這樣未免太麻煩,可以通過以下幾種方式改善:
    • 方法一:修改 package.json 中之前寫好的 start 語句
    "start":"webpack src/main.js dist/bundle.js --watch",
    
    • 方法二:新定義一個 watch 命令,這種方式根據官方文檔說明,由于調用的是之前自定義的 npm run start 命令,因此需要在 --watch 前額外添加 --
    # package.json
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start":"webpack src/main.js dist/bundle.js",
      "watch":"npm run start -- --watch"
    },
    

package.json

以第二種方式為例:
監(jiān)聽成功

此時則監(jiān)聽成功,修改 main.js 保存則實時會在 bundle.js 中顯示,頁面中刷新即可展示;ctrl + c 終止監(jiān)聽。

實時監(jiān)聽

使用配置文件
  • 為了看出效果,我們先把之前生成的 bundle.js 文件刪掉。
  • webpack-3.10.0 目錄下創(chuàng)建 webpack.config.js ,并輸入如下內容
#  webpack.config.js

var webpack = require("webpack");

module.exports = {
    entry:'./src/main.js', 
    output:{
        path:'./dist',        
        filename:'bundle.js'
    }
}

此時你的項目結構應該是這樣的,dist 目錄下 空空如也

dist 目錄下為空

  • 跑一下試試

    報錯

    原因是 output 中的路徑需要是絕對路徑 absolute path

  • 在配置文件中引入 path 模塊解決絕對路徑問題

    var webpack = require("webpack");
    var path = require("path");
    
    module.exports = {
        entry:'./src/main.js',
        output:{
            path:path.resolve(__dirname,'./dist'),
            filename:'bundle.js'
        }
    }
    
  • 由于添加了配置文件,因此需要修改一下 package.json 中的啟動命令 npm run start 更改為如下(因為配置文件中已經設置了路徑及文件名,因此不需要命令中再指定)

    "start":"webpack",
    
  • 跑一下


    跑跑

    同樣是創(chuàng)建了 bundle.js 文件

    效果是一樣的


CSS 處理
  • src 目錄下創(chuàng)建 main.css
    # main.css
    body{
        background: orange;
    }
    
  • 修改 main.js
    # main.js
    require('./main.css')
    
  • 使用 npm run watch 命令會報錯
    缺少 loader

    缺少 loader,這里引用官網說明:

loader 讓 webpack 能夠去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以將所有類型的文件轉換為 webpack 能夠處理的有效模塊,然后你就可以利用 webpack 的打包能力,對它們進行處理。
本質上,webpack loader 將所有類型的文件,轉換為應用程序的依賴圖(和最終的 bundle)可以直接引用的模塊。

  • 處理 css 需要安裝一個 css-loader 的包:
    npm install css-loader --save-dev
    
安裝成功
  • 安裝完成后需要在配置文件中進行處理,注意 module 屬性:
# webpack.config.js

var webpack = require("webpack");
var path = require("path");

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,  //  正則匹配 .css 后綴
            use:'css-loader'
        }]
    }
}

再跑一下

修改配置文件之后

看一下是否被打包到 bundle.js
bundle.js

可以看到 main.css 的樣式的確被打包到 bundle.js 中了,但為什么瀏覽器中沒有效果?

  • 安裝 style-loader
npm install style-loader --save-dev
  • 修改配置文件,注意:style-loader 需要寫在前面
    修改配置文件
  • 再調用命令
    npm run watch 
    
樣式已注入

將 ES6 代碼編輯為所有瀏覽器通用的代碼
  • main.js 內容改為一段 ES6 的代碼
    # main.js
    let a = 11;
    const b = 22;
    
    class Foo{
    
    }
    
  • 直接調用 npm run watch 會發(fā)現 bundle.js 中的代碼依舊為 ES6
    尚未安裝 ES6
  • 這時需要 Babel 這個工具

Babel 的作用就是將下一代的 JavaScript 語法轉換為現今瀏覽器兼容的語句

  • 首先安裝 Babel
    npm install --save-dev babel-loader babel-core
    
  • webpack.config.js 中添加一條規(guī)則:
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
    
    其中,test 用于判斷擴展名為 .js 的文件,exclude 表示不包括的文件。
    添加規(guī)則后,此時的 webpack.config.js 文件應該是這樣的
    添加規(guī)則
  • 安裝轉換 ES2015 及更高版本 JavaScript 語法的 env preset
    npm install babel-preset-env --save-dev
    
  • 在根目錄 webpack-3.10.0 下創(chuàng)建 .babelrc 文件,內容如下:
    {
      "presets": ["env"]
    }
    
創(chuàng)建 .babelrc
  • OK,現在執(zhí)行命令 npm run watch,可以看到我們之前 main.js 中的語句在 bundle.js 中已經成功轉換成通用語句了
    main.js

    bundle.js

    本節(jié)內容可直接參考 Babel 官網:https://babeljs.cn/

文件壓縮
  • 文件壓縮需要用 webpack 的插件來實現,比如 webpack 自帶一個 BannerPlugin 插件,用于添加頂部注釋,首先在 webpack.config.js 中添加如下代碼:
    plugins:[
      new webpack.BannerPlugin('頂部注釋插件')
    ]
    
  • 重新打包 npm run watch,成功后,bundle.js 中頂部出現注釋
    添加成功
  • webpack 有個自帶的插件 UglifyJsPlugin 用于壓縮文件
plugins:[
  new webpack.BannerPlugin('頂部注釋插件'),
  new webpack.optimize.UglifyJsPlugin()
]

重新打包后的 bundle.js

壓縮后的 bundle.js

  • 然而我們在開發(fā)調試階段是不需要壓縮代碼的,因此需要對開發(fā)環(huán)境和線上環(huán)境做個區(qū)分,開發(fā)環(huán)境不壓縮代碼,線上環(huán)境才壓縮
    if(process.env.NODE_ENV === 'production'){
        module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
    }
    
    如果是線上環(huán)境,則將 UngifyJsPlugin 插件填入 webpackplugins
  • 回到命令行調用命令
    set NODE_ENV=production  // 設置為生產環(huán)境, windows 系統(tǒng)
    npm run watch
    
切換線上環(huán)境并打包
  • 我們可以直接在 package.json 中添加腳本命令(我嘗試了幾種寫法,發(fā)現只有這樣是有效的,不知道為什么。此外,有時這樣也不好用,需要在命令行中手動制定一次 set NODE_ENV=production,之后調用 npm run production 就有效了)
    "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1",
      "start": "webpack",
      "watch": "npm run start -- --watch",
      "production":"set NODE_ENV=production && npm run watch",
      "development":"set NODE_ENV=development && webpack --watch"
    }
    

這樣在命令行中通過 npm run development 即可切換為開發(fā)環(huán)境(代碼不壓縮),npm run production 就是生產環(huán)境(代碼壓縮)

開發(fā)生產環(huán)境切換

  • webpack.config.js 簡單做一下整理
var webpack = require("webpack");
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production'

module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'bundle.js'
    },
    module:{
        rules:[{
            test:/\.css$/,
            use:['style-loader','css-loader']
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('頂部注釋插件'),
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

SASS 處理
  • 安裝相關 loader
    npm install sass-loader node-sass webpack --save-dev
    
  • 這里我在安裝 node-sass 時失敗了,改為分別單獨安裝,node-sass 使用淘寶鏡像 其他解決方案
    # 安裝 sass-loader
    npm install sass-loader --save-dev
    # 安裝 node-sass
    npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
    
  • 修改配置文件
    # webpack.config.js
    
      module:{
          rules:[{
              test: /\.scss$/,
              use: [
                  "style-loader", // creates style nodes from JS strings
                  "css-loader", // translates CSS into CommonJS
                  "sass-loader" // compiles Sass to CSS
              ]
          },{
              test:/\.css$/,
              use:['style-loader','css-loader']
          },{ 
              test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
          }]
      },
    
  • 修改 mian.js
    # main.js
    require('./main.scss')
    
  • 修改 main.cssmain.scss 并輸入 scss 語句測試
    # main.scss
    $default:pink;
    body{
        background:$default
    }
    

重新打包,OK


sass 打包

CSS 與 JS 分離
  • 通常 webpack 建議所有文件都打包成一個單獨的文件,這樣可以減少網絡請求。但如果有需要分類打包的話,需要使用 webpack 的一個外部插件 ExtractTextWebpackPlugin
  • 安裝
    npm install --save-dev extract-text-webpack-plugin
    
  • 修改配置文件,注意注釋部分
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin"); //  引入插件
var path = require("path");
var isProduction = process.env.NODE_ENV === 'production';


module.exports = {
    entry:'./src/main.js',
    output:{
        path:path.resolve(__dirname,'./dist'),
        filename:'[name].js'
    },
    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({        //  使用插件
                fallback: "style-loader",           //  用哪個 loader 加載
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction       //  是否壓縮 css
                    }},
                    "sass-loader"]                  //  將資源轉換為 css
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        }]
    },
    plugins:[
        new webpack.BannerPlugin('頂部注釋插件'),
        new ExtractTextPlugin("[name].css"),        //  輸出為 style.css 文件
    ]
}

if(isProduction){
    module.exports.plugins.push(new webpack.optimize.UglifyJsPlugin())
}

文件處理 file-loader 與 url-loader
  • 首先在 src 目錄下新建 images 目錄并存入兩個大小不一的圖片

    新建目錄并存入圖片

  • index.htmlmain.scss 中引入兩個圖片

    index.html

    main.scss

  • 安裝 file-loader

    npm install --save-dev file-loader
    
  • 修改配置文件

    module:{
        rules:[{
            test: /\.scss$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: [{
                    loader:"css-loader",
                    options:{
                        minimize:isProduction
                    }},
                    "sass-loader"]
            })
        },{ 
            test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" 
        },{
            test:/\.png|jpe?g|gif$/,    // 匹配的圖片格式
            use:['file-loader']         //  使用 file-loader
        }]
    }
    
  • 執(zhí)行 npm run production,圖片被打包并以 hash 方式重新命名

    圖片打包

    打包后的 main.css

  • 也可以讓圖片以原有名字和后綴保存:

    {
          test:/\.png|jpe?g|gif$/,
          use:[{
              loader:'file-loader',
              options:{
                  name:'[name].[ext]'  // 以原有名字和后綴保存
              }
          }]
    }
    
原有名字和后綴
  • 也可以創(chuàng)建指定目錄存放文件
    options:{
      name:'images/[name].[ext]'
    }  
    
    或,注意 outputPath/ 不能少
    options:{
      name:'[name].[ext]',
      outputPath:'images/'
    }
    

    效果就是這樣


    我是效果
  • 至于 url-loader ,它可以限制圖片的大小,小于一定值的圖片將以 DataURL 直接嵌入在頁面中,減少請求數
  • 安裝
    npm install --save-dev url-loader
    
  • 修改配置文件
    use:[{
        loader:'url-loader',
        options:{
            limit:20480,    // 小于該值將嵌入頁面
            name:'[name].[ext]',
            outputPath:'images/'
        }
    }]
    
  • 打包后可看到只有一個圖片被打包,另一個圖片直接嵌在了頁面中:


    只有一張圖片引入

    嵌入頁面

多入口及自動清理
  • 嘗試改一下入口屬性
    entry:{app:'./src/main.js'},
    

這樣生成的 jscss 文件將變成 app.jsapp.css

  • 先安裝一個 jquery 包,注意名字小寫
    npm install --save-dev jquery
    
  • 修改配置文件
    entry:{
        main:'./src/main.js',    // 將 main.js 打包成 main
        vendor:'jquery'          // 將 jquery 打包成 vendor
    }
    
多個入口
  • 自動清理需要 clean-webpack-plugin 插件
    npm install clean-webpack-plugin --save-dev
    
  • 如果我們在生成的文件中添加 hash 值會發(fā)現,每次打包由于 hash 導致名字的不同,進而會出現不同名的同文件,這顯然不是我想要的。這個插件就可以用于每次打包前先清除指定目錄或文件,避免重復。
  const path = require('path');
  const HtmlWebpackPlugin = require('html-webpack-plugin');
+ const CleanWebpackPlugin = require('clean-webpack-plugin');

  module.exports = {
    entry: {
      app: './src/index.js',
      print: './src/print.js'
    },
    plugins: [
+     new CleanWebpackPlugin(['dist']),
      new HtmlWebpackPlugin({
        title: 'Output Management'
      })
    ],
    output: {
      filename: '[name].bundle.js',
      path: path.resolve(__dirname, 'dist')
    }
  };
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容