配置Webpack4支持ES6/TypeScript/異步文件引用加載

從零開始的配置

因爲Webpack以及它的周邊工具babel等更新過快,在當前的時間線來看,不少相關的文章已被版本所淘汰,已經不足以借鑑來搭建一個能夠正常使用的環境,因此打算寫來記錄一下。html

在寫這篇文章的時候我會同步搭建本地環境,儘可能避免有略過的細節部分。node

環境起步

熟悉初始化項目的親可直接跳過。webpack

首先請保證node與npm版本不要過舊,我目前的版本: node v10.15.3 / npm 6.4.1git

建立並進入文件夾my-webpack 並在命令行github

npm init -y 
複製代碼

而後打開生成的package.json 修改scripts的內容,新增build命令,一下子咱們會用到web

"scripts": {
    "build": "webpack"
},
複製代碼

安裝webpack環境,推薦使用yarn安裝,語法與npm差很少,但好處在於安裝快,排查錯誤方便。typescript

yarn add webpack webpack-cli --dev
或
npm install webpack webpack-cli --save-dev
複製代碼

安裝完成後在當前目錄建立webpack.config.js 寫入基礎配置npm

const path = require('path');

module.exports = {
    mode : 'development',//開發環境模式
    entry : {
        main : './src/index.js'//入口配置
    },
    output : {
        filename : 'bundle.js',//輸出配置
        path : path.resolve(__dirname, './build')
    }
}
複製代碼

這時候這個只具有雞肋功能的webpack環境咱們就搭建好了,接下來咱們將給雞肋插上 小翅膀 ʚɞjson


配置編譯ES6的Loader

此處先不介紹實際代碼,由於隨着版本迭代,文章中的代碼語法等終究會被淘汰,咱們應該學會如何去使用新版本,或者說躲過舊版本語法的坑數組

打開github搜索babel-loader,第一個結果就是了,打開後向下滾動查看它的介紹:

它已經清楚的介紹了此loader的支持環境 須要webpack 4做爲基礎環境支持

咱們按照它的介紹安裝loader,因爲webpack剛纔咱們已經安裝過了,此處能夠去掉,但咱們須要作瀏覽器兼容,在命令行中多加入一個 @babel/polyfill的擴展 以下↓

yarn add babel-loader @babel/core @babel/preset-env @babel/polyfill --dev
複製代碼

安裝完成後咱們開始修改webpack.config.js

讓其支持Loader的編譯,此處你不須要記得清楚loader如何配置,在剛纔babel-loader介紹安裝方式的下方有教你如何配置,直接拿來粘貼便可:

entry..
output...
//重複代碼略過 同級寫入
module : {
    rules : [
        {
            test: /\.js$/,
            exclude: /(node_modules)/,
            use: {
                loader: 'babel-loader'
            }
        }
    ]
}
複製代碼

實際使用webpack.config.js的配置項很是之多,babel-loader的options也有不少須要配置的,此處咱們已經刪掉了loader中options這個鍵值,在當前目錄下新建 .bebelrc 文件

配置它的options:

// .babelrc
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": ["> 1%","last 2 versions","Android >= 3.2", "Firefox >= 20","iOS 7"]
                },
                "corejs":2,
                "useBuiltIns": "usage"
            }
        ]
    ]
}
複製代碼

配置參數的介紹

  • @babel/preset-env: 是babel編譯的基礎庫,它下個對象中的參數,是針對於它默認配置的重定義 ↓
  • targets:即在編譯時根據咱們的需求寫入瀏覽器版本進行兼容
  • useBuiltIns:默認值爲false,它很重要,咱們此處改成"usage",即爲按需引入:是否只編譯你腳本中使用過的API,如Promise,若是爲false則不會使用polyfill進行編譯
  • corejs:配合useBuiltIns使用,告訴它編譯時使用哪兒個core-js的版本做爲核心庫進行編譯,若是不聲明也能夠正常運行,可是命令行會有警告提示說這樣作是有隱患的,因此咱們在此處聲名大版本爲 2 便可,那麼如何查看咱們corejs的大版本呢,它又是何時安裝的呢?其實在安裝@babel/polyfill的時候就已經被自動安裝上了,咱們只須要找到擴展node_moudules/@babel/polyfill 查看它package.json中記錄的文件依賴,它裏面會清楚寫着core-js的版本號,而corejs咱們也能夠手動安裝,但默認版本corejs已是3起步了,因此經過@babel/polyfill默認安裝便可

除了@babel/preset-env還有其餘可使用的編譯庫,英文好的能夠直接看官方文檔,或者簡單瞭解下配置的其餘參數

編譯代碼看效果

建立src文件夾,並新建index.js 咱們試一試Promise與ES6語法可否在IE下正常運行

//index.js
const imgPromise = (imgSrc) => {
    return new Promise((resolve, reject)=>{
        const img = new Image();
        img.onload = () =>{
            resolve(img);
        }
        img.onerror = () => {
            reject();
        }
        img.src = imgSrc;
    });
}
const newImgSrc = 'http://b.hiphotos.baidu.com/image/h%3D300/sign=77d1cd475d43fbf2da2ca023807fca1e/9825bc315c6034a8ef5250cec5134954082376c9.jpg';
const newImg = new imgPromise(newImgSrc).then((img)=>{
    document.body.appendChild(img);
},()=>{
    console.log("img error");
});
複製代碼

編譯輸出它,即在目錄中生成build文件夾與bundle.js文件 ↓

npm run build

在build文件夾中建立index.html,引入bundle.js

(html文件能夠經過配置webpack的HtmlWebpackPlugin來自動生成,此處手動建立,只爲看到編譯效果)

而後使用IE打開index.html文件便可看到圖片加載,到這裏,咱們ES6語法 & API的編譯功能就大功告成了~


支持TypeScript

同配置babel-loader的方法同樣,直接去github搜索編譯TypeScript的ts-loader 安裝它

yarn add ts-loader typescript --dev
複製代碼

在webpack配置文件的rules數組中增長ts-loader

//webpack.config.json

rules:[
    ...babel-loader,
    { 
        test: /\.tsx?$/,
        exclude: /(node_modules)/,
        loader: "ts-loader"
    }
]
複製代碼

同理,在項目根目錄新增一個 tsconfig.json 配置ts-loader

//tsconfig.json
{
    "compilerOptions": {
        "module": "UMD",
        "target": "es5",
        "sourceMap": true,
        "allowJs": true
    },
    "exclude": ["node_modules", "dist", "build", "mock"]
}
複製代碼
  • module:模塊的引入方式
  • target:編譯後的運行環境
  • allowJs:容許編譯JS文件
  • 更多配置介紹 中文 / 英文

開始編譯TypeScript

在src目錄建立一個TS文件

//test.ts
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

export default greeter;
複製代碼

而後經過import形式引入它

//index.js
import greeter from './test.ts'

...省略以前測試Promise的代碼


let user = { firstName: "Jane", lastName: "User" };
console.log(greeter(user));
複製代碼

執行編譯後咱們可直接打開build/index.html文件,打開控制檯查看console

便可看到TS文件被成功編譯,IE11也可正常使用,還能夠在控制檯看到它編譯後的代碼:

var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;(function (factory) {
    if ( true && typeof module.exports === "object") {
        var v = factory(__webpack_require__("./src sync recursive"), exports);
        if (v !== undefined) module.exports = v;
    }
    else if (true) {
        !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__, exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
				__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
				(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
    }
})(function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    function greeter(person) {
        return "Hello, " + person.firstName + " " + person.lastName;
    }
    exports.default = greeter;
});
複製代碼

腳本異步引用加載

本文的最後一個環節,也是開發中會常常用到的功能

若是一次加載大量的文件,或有些代碼並不須要在頁面初次進來的時候進行加載,能夠很好地優化項目的加載速度。

在output中新增chunkFilename 意爲分割後文件的命名規則

//webpack.config.js
output:{
    ...,
    chunkFilename: '[name].bundle.js'
}
複製代碼

安裝@babel/plugin-syntax-dynamic-import並擴展babel-loader配置,使其支持動態文件引入

yarn add @babel/plugin-syntax-dynamic-import --dev

//擴展.babelrc 新增plugins參數
{
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "browsers": ["> 1%","last 2 versions","Android >= 3.2", "Firefox >= 20","iOS 7"]
                },
                "corejs":2,
                "useBuiltIns": "usage"
            }
        ]
    ],
    "plugins": ["@babel/plugin-syntax-dynamic-import"]
}
複製代碼

經過import動態引入文件 webpackChunkName註釋的值test 會在 chunkFilename的[name]中使用

//index.js增長如下代碼 
function getTest(obj){
    return import(/* webpackChunkName: "test" */ './test.ts').then(({default:test})=>{
        console.log(test(obj));
    }).catch(error=>{
        console.log(error);
    })
}
//或者使用async/await來處理異步插件 
async function getTest(obj){
    await import(/* webpackChunkName: "test" */ './test.ts').then(({default:test})=>{
        console.log(test(obj));
    }).catch(error=>{
        console.log(error);
    })
}

document.body.onclick = () =>{
    let user = { firstName: "Jane", lastName: "User" };
    getTest(user);
}
複製代碼

此時命令行運行

npm run build

輸出文件

bundle.js  91.5 KiB

test.bundle.js  1.95 KiB
複製代碼

此時咱們能夠打開index.html 開啓F12看到頁面只加載了bundle.js

當你點擊了圖片時會動態加在test.bundle.js,並在命令行中輸出

Hello, Jane User

簡單的代碼分割與動態加載就實現了,但實際業務中存在不少公用的腳本,不能將全部的代碼都進行分割

而我這裏只寫了異步加載的代碼分割,還有同步代碼的分割可進行設置,有不少參數須要配置,須要耐心的瞭解

webpack-splitChunks


尾兒

webpack的配置常常隨着時間變化而改變,但願能避免配置新版本環境時沒必要要的踩坑 ~

而要寫全全部功能的配置須要大量的時間,暫且沒有精力,因此目前先寫這種雖然精簡卻能用到的功能。

只要學會如何本身去找到配置babel-loader的方法,配置其餘CSS-loader等也均可以一併學會了。

相關文章
相關標籤/搜索