webpack 4 入門教程一

什麼是 Webpack? 
webpack 是一個靜態模塊打包器(module bundler)
作用:
① 它能將多個js文件打包成一個文件(傳統開發會需要引入很多js,導致網頁加載需要發起多次http請求而是加載速度變慢)
② 解決傳統的依賴引用混亂問題,有時候傳統js引用必須要按規定順序加載,
③ 可以支持css和less的加載,圖片處理(可以將較小的圖片轉成base64,減少http請求)
④ 可以通過模板引擎插件html-webpack-plugin生成HTML頁面,html-webpack-plugin默認支持ejs格式的模板文件,如果你想使用其它格式的模板文件,那麼需要在webpack配置裏設置好相應
的loader

從 webpack v4.0.0 開始,可以不用引入一個配置文件。
然而,webpack 仍然還是高度可配置的。在開始前你需要先理解四個核心概念:

入口(entry)
輸出(output)
loader
插件(plugins)

1.先安裝node.js

https://nodejs.org/en/download

查看版本

$ node -v
v10.14.2

$ npm -v
6.5.0

2.使用淘寶鏡像

$ npm install -g cnpm --registry=https://registry.npm.taobao.org

3.安裝webpack

$ cnpm install webpack -g

查看版本

$ webpack -v
4.41.5

安裝babel

cnpm install -D babel-loader@7
//cnpm install -D babel-loader會默認安裝到[email protected]版本,需要babel7.x支持
cnpm install -D babel-core 
cnpm install -D babel-preset-env
cnpm i babel-plugin-transform-runtime

4.創建項目
$ mkdir webtest
創建src文件夾
$ cd webtest
$ mkdir src5.新建文件
*1 webtest下新建index.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Webpack入門</title>
    </head>
    <body>
        <div id="webContent"></div>

        <script type="text/javascript" src="./src/index.js" charset="utf-8"></script>
    </body>
</html>

*2 src下新建getById.js內容如下

function getById(id) {
  return document.getElementById(id);
}

export default getById;

*3 src下新建index.js內容如下

import getById from './getById.js';

getById('webContent').innerHTML = 'Hello Webpack!!!';

6.初始化
$ npm init
一直按回車即可,最後會生成package.json
 

{
  "name": "webtest",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}

7.打包,在webtest執行webpack
結果是會生成一個dist文件夾,裏面有一個main.js文件

這時會有一個警告

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. 
Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. 
Learn more: https://webpack.js.org/configuration/mode/

就是沒有指定打包模式,默認會以production模式打包,可以在命令行指定或在配置文件指定
模式可選 string = 'production': 'none' | 'development' | 'production'

module.exports = {
  mode: 'development'
};


webpack --mode=development

C:\Users\01\Desktop\webtest>webpack --mode=development
Hash: f514556032677b335a67
Version: webpack 4.41.5
Time: 238ms
Built at: 2020-01-04 11:08:12
  Asset      Size  Chunks             Chunk Names
main.js  4.58 KiB    main  [emitted]  main
Entrypoint main = main.js
[./src/getById.js] 90 bytes {main} [built]
[./src/index.js] 92 bytes {main} [built]

development模式打包會生成很詳細的main.js文件默認的打包配置webpack.config.js如下

const path = require('path');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'
  }
};

這個文件沒有,如果只執行webpack也是一樣的

9.修改index.html的js引用

<script type="text/javascript" src="./dist/main.js" charset="utf-8"></script>

然後就可以在瀏覽器打開index.html,就會頁面看到

Hello Webpack!!!

至此,我們將多個js打包合併就完成了,如果有興趣可以查看main.js裏面的內容

10.查看main.js內容,格式化後如下

!
function(e) {
    var t = {};
    function n(r) {
        if (t[r]) return t[r].exports;
        var o = t[r] = {
            i: r,
            l: !1,
            exports: {}
        };
        return e[r].call(o.exports, o, o.exports, n),
        o.l = !0,
        o.exports
    }
    n.m = e,
    n.c = t,
    n.d = function(e, t, r) {
        n.o(e, t) || Object.defineProperty(e, t, {
            enumerable: !0,
            get: r
        })
    },
    n.r = function(e) {
        "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, {
            value: "Module"
        }),
        Object.defineProperty(e, "__esModule", {
            value: !0
        })
    },
    n.t = function(e, t) {
        if (1 & t && (e = n(e)), 8 & t) return e;
        if (4 & t && "object" == typeof e && e && e.__esModule) return e;
        var r = Object.create(null);
        if (n.r(r), Object.defineProperty(r, "default", {
            enumerable: !0,
            value: e
        }), 2 & t && "string" != typeof e) for (var o in e) n.d(r, o,
        function(t) {
            return e[t]
        }.bind(null, o));
        return r
    },
    n.n = function(e) {
        var t = e && e.__esModule ?
        function() {
            return e.
        default
        }:
        function() {
            return e
        };
        return n.d(t, "a", t),
        t
    },
    n.o = function(e, t) {
        return Object.prototype.hasOwnProperty.call(e, t)
    },
    n.p = "",
    n(n.s = 0)
} ([function(e, t, n) {
    "use strict";
    n.r(t),
    (function(e) {
        return document.getElementById(e)
    } ("webContent")).innerHTML = "Hello Webpack!!!"
}]);

function前面有個感嘆號是什麼意思呢?
我們來看一下,一般我們定義函數有2種方法
第1種

function funcName () {

}

第2種

var funcName = function() {

}

console.log(funcName()); // 會在控制檯輸出undefined,因此function默認返回值是undefined
那麼我們怎麼在定義的時候就執行這個函數呢,一般就是FunctionName(),我們改變一下
function funcName () {}(),這樣會報錯,應該這樣

(function funcName () {

})();

這樣控制檯就會打印出undefined了,也就是定義時就直接執行了

我們加個感嘆號試試
console.log(!funcName()); // 控制檯當然就會打印出true,就是一個取反運算

我們再修改一下我們的定義

!function funcName(){
  
}();

把這段代碼放到Chrome的console裏,發現會打印處true
因此,感嘆號的作用就是將函數定義給編譯了,就是將

function funcName(){
  
}

編譯爲funcName這個函數了,然後等於執行!funcName(),
因此感嘆號的作用就是執行一個取反操作,函數該怎麼定義還是怎麼定義

10.假如要export多個函數,並import,可以修改一下

getById.js

function getById(id) {
	return document.getElementById(id);
}
function getValueById(id) {
	return document.getElementById(id).value;
}

export {getById,getValueById};

index.js

import {getById, getValueById} from './getById.js';

getById('webContent').innerHTML = 'Hello Webpack!!!';

getById('webContent2').innerHTML = getValueById("login");

index.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>Webpack入門</title>
    </head>
    <body>
		<div id="webContent"></div>
		<div id="webContent2"></div>
		<input id="login" value="登錄">

        <script type="text/javascript" src="./dist/main.js" charset="utf-8"></script>
    </body>
</html>

最終顯示

11.使用webpack-dev-server來進行本地自動熱更新開發

安裝webpack-dev-server

$ cnpm install -g webpack-dev-server

修改package.json增加serve

"scripts": {
    "serve": "webpack-dev-server --open --mode development"
}

修改webpack.config.js增加devServer

devServer: {
  contentBase: path.join(__dirname, "dist"), // 默認本地服務器所在的根目錄
  port: 8084,      // 端口號,默認8080
  hot: true
}

安裝html-webpack-plugin和clean-webpack-plugin插件

$ cnpm install -g html-webpack-plugin clean-webpack-plugin

添加插件配置

const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const {CleanWebpackPlugin} = require('clean-webpack-plugin');  //清除
// 注意引用CleanWebpackPlugin必須是對象,否則會報錯TypeError: CleanWebpackPlugin is not a constructor

plugins: [
    new HtmlWebpackPlugin({
    	title: '首頁',
    	template: './index.html'  // 以當前目錄的index.html爲編譯模板
    }),
    new CleanWebpackPlugin()
],

運行npm run serve,報錯Error: Cannot find module 'webpack/lib/node/NodeTemplatePlugin'

網上查了,webpack必須本地安裝

$ cnpm install webpack

最終運行npm run serve效果

默認顯示模式是iframe, 就是頁面有修改,直接用iframe加載修改後的頁面,頂部會顯示提示信息,狀態欄不會改變

如果不需要這樣方式,可以在devServer添加配置選項:

inline: true

這樣就不會有頂部提示了,文件修改就刷新整個頁面

12.添加2個有用的插件

banner-plugin(webpack 內置插件,不用獨立安裝)
作用:在輸出的打包壓縮的JS代碼內嵌入版權識別註釋
引入:
  const webpack=require('webpack')
plugins[]配置屬性加入
  new webpack.BannerPlugin('Made by Andy 2020')


作用: 打包時複製文件到指定目錄
var CopyWebpackPlugin = require('copy-webpack-plugin');
plugins[]配置屬性加入
new CopyWebpackPlugin([
  {from:'./src', to:'./dest'}
])

13.實現多頁面打包編譯生成

比如login.html和index.html分別都有它們的js(login.js, index.js)

我們可以配置如下

src
 - pages
   - login.html
   - index.html
 - js
   login.js
   index.js

webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');     //生成html文件
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); //清除

module.exports = {
  mode: 'production',
  entry: {
    index: './src/js/index.js',
    login: './src/js/login.js',
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].js'
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
		filename: 'index.html',
    	title: '首頁',
    	template: './src/pages/index.html',  // 以index.html爲編譯模板
		chunks: [
		  'index'
		]
    }),
    new HtmlWebpackPlugin({
		filename: 'login.html',
    	title: '登錄頁',
    	template: './src/pages/login.html',  // 以login.html爲編譯模板
		chunks: [
		  'login'
		]
    }), 
  ],
  devServer: {
	contentBase: path.join(__dirname, "dist"),      // 默認本地服務器所在的根目錄
	historyApiFallback: true,   // 是否跳轉到index.html
	inline: true,    // 
	port: 8083,      // 端口號,默認8080
	hot: true
  },
};

src/js/getById.js

function getById(id) {
	return document.getElementById(id);
}
function getValueById(id) {
	return document.getElementById(id).value;
}

export {getById,getValueById};

src/js/index.js

import {getById} from './getById.js';

getById('webContent').innerHTML = 'index - Hello Webpack!!!';

src/js/login.js

import {getById} from './getById.js';

getById('webContent').innerHTML = 'login - Hello Webpack!!!';

src/pages/index.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<meta http-equiv="X-UA-Compatible" content="ie=edge">
		<title>首頁</title>
    </head>
    <body>
		<div id="webContent"></div>
    </body>
</html>

src/pages/login.html

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>登錄</title>
    </head>
    <body>
        <div id="webContent"></div>
    </body>
</html>

最終效果

這是自動打開首頁,因爲配置了historyApiFallback: true,如果要打開login.html,http://localhost:8083/login.html

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章