webpack4搭一個簡易SPA應用

開篇

webpack 在現在的前端開發中,算是不可繞過的一個工具吧。特別是在開發SPA應用的時候,不管是開發環境,仍是打包上線,都十分依賴webpack。javascript

開發環境

win10css

node -v: 10.15.0html

npm -v: 6.4.1前端

Let's go。vue

體驗0配置

進入到工做目錄,而後建立項目java

mkdir spa-webpack-demo
複製代碼

初始化node

npm init -y
複製代碼

先來體驗下 webpack40配置:webpack

安裝 webpackgit

npm i -D webpack
複製代碼

安裝好 webpack 依賴後,建立 src 文件夾,並在 src 中新建一個 index.jsgithub

mkdir src
cd src
type nul > index.js
複製代碼

修改 package.json,在 scripts選項中,添加兩個命令:

"dev": "webpack --mode=development",
"prod": "webpack --mode=production"
複製代碼

好,完事了。接下來跑命令行,測試一下

npm run dev
複製代碼

正常狀況下,控制檯會有一段以下提示,由於 webpack 命令須要依賴 webpack-cli,咱們安裝便可

Do you want to install 'webpack-cli' (yes/no): yes
複製代碼

webpack-cli安裝完成以後,會自動繼續跑咱們的 npm run dev 指令,便可看到項目中多了一個 dist 目錄,並且多了一個 main.js

接下來繼續嘗試 npm run prod,能夠看到 dist/main.js 已被壓縮。

這就是 webpack 號稱的零配置,主要的工做就是定義了默認的entry路徑src/index.js,定義了默認的output路徑dist/main.js,而後加了一個mode參數,根據mode參數的不一樣幫咱們添加一些預置的打包規則。

按部就班

上述的流程裏,只是體驗了一把零配置的感受,連html文件都沒有,這裏開始加上。

加個index.html

在根目錄新建 index.html,隨便編寫點內容

type nul > index.html
複製代碼

說處處理 html 文件,確定少不了 html-webpack-plugin, 安裝它

npm i -D html-webpack-plugin
複製代碼

而後再項目根目錄新建一個 webpack.config.js,webpack會自動使用它

type nul > webpack.config.js
複製代碼

webpack.config.js的內容以下

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    module: {
        rules: []
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: 'index.html'
        })
    ]
}
複製代碼

執行npm run dev,便可看到 dist文件夾多了個index.html,這個index.html自動引入了打包後的dist/main.js

加個本地服務器

index.html 是生成了,可總不能每次手動打開它在瀏覽器裏面預覽吧, webpack 官方推薦咱們用 webpack-dev-server作服務器,安裝它

npm i -D webpack-dev-server
複製代碼

安裝成功後, 修改webpack.config.js,添加 devServer 選項 和 webpack.HotModuleReplacementPlugin 插件。

對於文件中已經添加過的內容,後面我都會用註釋表示。

const path = require('path');
const webpack = require('webpack');

function resolve(dir) {
    return path.join(__dirname, './', dir)
}

module.exports = {
    // module - 略
    devServer: {
        contentBase: resolve('dist'), // 根目錄
        hot: true,   // 是否開啓熱替換,無須手動刷新瀏覽器
        port: 8081,    // 端口
        open: true,     // 是否自動打開瀏覽器
        noInfo: true   // 不提示打包信息,錯誤和警告仍然會顯示
    },
    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        // HtmlWebpackPlugin - 略
    ]
}
複製代碼

而後修改 package.json scriptsdev 選項

"dev": "webpack-dev-server --mode=development",
複製代碼

注意:當 devServerhot參數爲true時,記得要在插件裏添加new webpack.HotModuleReplacementPlugin(), 或者你能夠在命令行中帶上hot參數,這樣就不須要本身再往plugins中添加插件了。

"dev": "webpack-dev-server --hot --mode=development"
複製代碼

而後npm run dev,就能夠嘗試靜態資源熱替換功能了。

處理js, css 等其餘靜態資源

首先咱們要清楚一點,webpack 它自己是不知道應該如何處理靜態資源的,可是它提供了loaderplugin機制。

loader 的做用,顧名思義:加載器,就是匹配到的靜態資源,都要通過loader的內部處理,再返回處理以後的結果。我以爲,loader像是一個攔截器。

說到js,咱們會想到 babel-loaderbabel-loader是幹嘛的?常規操做是,將匹配到的js文件的ES6代碼 根據 babelrc文件內的配置 編譯成對應的 ES5代碼。

咱們這裏先添加一個.babelrc文件

新增.babelrc文件

type nul > .babelrc
複製代碼

編輯 .babelrc 內容

{
    // 預設置,告訴Babel要轉換的源碼使用了哪些新的語法特性
    // targets, useBuiltIns 等選項用於編譯出兼容目標環境的代碼
    // 其中 useBuiltIns 若是設爲 "usage"
    // Babel 會根據實際代碼中使用的 ES6/ES7 代碼,以及與你指定的 targets,按需引入對應的 polyfill
    // 而無需在代碼中直接引入 import '@babel/polyfill',避免輸出的包過大,同時又能夠放心使用各類新語法特性。
    "presets": [
        ["@babel/preset-env", {
            // modules 是否 將 ES6 的 import/export模塊化 轉爲 babel 的 CommonJs 規範模塊化
            "modules": false,
            "targets": {
                // "> 1%" : 支持市場份額超過1%的瀏覽器, 
                // ""last 2 versions"": 支持每一個瀏覽器最後兩個版本
                // "not ie <= 8": 在以前條件的瀏覽器中,排除 IE8 如下的瀏覽器
                "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
            },
            "useBuiltIns": "usage"
        }]
    ],
    // 所用插件
    // transform-runtime 插件表示無論瀏覽器是否支持ES6,只要是ES6的語法,它都會進行轉碼成ES5
    // 這個是須要優化的
    "plugins": ["@babel/plugin-transform-runtime"]
}
複製代碼

安裝 babel 依賴,注意:

babel 7+ 已經廢棄了presets 中 stage-x 的用法,改成在plugins中添加。而且應用了npm scope包,代碼所有在 @babel 中,避免之前那種 babel-preset-xxx, babel-plugin-xxx 的用法

最新的 babel-loader 版本是8+,須要依賴 babel-core 版本7+,包名爲 @babel/core, 版本6+的包名爲 babel-core

再分析上面的 .babelrc 文件,它用到了@babel/preset-env, @babel/plugin-transform-runtime, 這些依賴都要咱們安裝好

若是使用了 @babel/preset-env,則不支持在 plugins 中 添加 stage-x

npm i -D babel-loader @babel/core @babel/preset-env @babel/plugin-transform-runtime
複製代碼

談到css,咱們就應該 想到 style-loadercss-loader。先安裝它們

npm i -D style-loader css-loader
複製代碼

再安裝 url-loader 用於解析靜態資源,如圖片,字體等

npm i -D url-loader
複製代碼

而後修改 webpack.config.jsrules, 添加以下代碼

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                loader: 'babel-loader', 
                include: [
                    resolve('src'),
                    resolve('node_modules/webpack-dev-server/client')
                ]
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                exclude: [],
                options: {
                    limit: 10000,
                    name: 'img/[name].[hash:7].[ext]'
                }
            }
        ]
    },
    // devServer - 略
    // plugins - 略
}
複製代碼
接下來準備開發了,用 vue 吧。

vue 就不用裝在 devDependencies 中了。

npm i -S vue 
// vue-loader 依賴 vue-template-compiler 和 vue-style-loader
npm i -D vue-loader vue-template-compiler vue-style-loader
複製代碼

修改 webpack.config.js, 添加 以下代碼

const { VueLoaderPlugin } = require('vue-loader');

module.exports = {
    resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
            '@': resolve('src')
        }
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            
            // 其餘 - 略
        ]
    },
    // devServer - 略
    plugins: [
        // 加在最前面
        new VueLoaderPlugin()
        
        // 其餘 - 略
    ]
}
複製代碼

src 下 新建一個 views 目錄 和 assets 目錄,

我在 assets 目錄下,增長了一個 logo.png 文件

views下建立一個 myTest 組件,myTest/index.vue, 編輯 index.vue

<template>
    <div>
        <i class="logo"></i>
    </div>
</template>

<script>
export default {
    name: 'myTest'
}
</script>

<style scoped>
    .logo {
        display: block;
        margin: auto;
        width: 400px;
        height: 400px;
        background: url(../../assets/logo.png);
    }
</style>
複製代碼

src 目錄下新建一個 App.vue, 內容以下

<template>
  <div id="app"> <my-test></my-test> </div> </template>

<script>
import myTest from "./views/myTest/index";

export default {
  name: "App",
  components: {
    myTest
  }
};
</script>
複製代碼

編輯 src 目錄下的 index.js,內容以下:

import Vue from 'vue';

import App from './App';

new Vue({
    el: '#app',
    render: h => h(App)
})
複製代碼

最後npm run dev,查看效果。

錦上添花

添加 打包進度條 信息,以下
npm i -D progress-bar-webpack-plugin
複製代碼

修改 webpack.config.js

const ProgressBarPlugin = require('progress-bar-webpack-plugin');

// ....

plugins: [
    // 其餘 - 略
    new ProgressBarPlugin()
]
複製代碼
添加 打包結果消息通知
npm i -D webpack-build-notifier
複製代碼

修改 webpack.config.js

const WebpackBuildNotifierPlugin = require('webpack-build-notifier');

// ....

plugins: [
    // 其餘 - 略
    new WebpackBuildNotifierPlugin()
]
複製代碼
歸類打包信息
npm i -D webpack-dashboard
複製代碼

修改 webpack.config.js

const DashboardPlugin = require('webpack-dashboard/plugin');

// ....

plugins: [
    // 其餘 - 略
    new DashboardPlugin()
]
複製代碼

修改 package.json

"dev": "webpack-dashboard -- webpack-dev-server --mode=development"
複製代碼

這個我使用了,感受效果不是很理想啊,會新開一個窗口,並且還不能滾動查看信息,不清楚是否是哪裏用錯了。

效果如圖:

整個代碼結構如圖:

還沒有完成的功能

  1. production 環境,須要使用 mini-css-extract-pluginoptimize-css-assets-webpack-plugin 插件,抽離並優化 css 文件
  2. production 環境,須要使用 UglifyJsPlugin 插件,壓縮 js 文件,這個插件容許多核編譯
  3. production 環境,須要使用 optimization 選項 splitChunks
  4. vue-routervuex 的引入
  5. 等等

寫在最後

但願本文的流程能幫助到有須要的讀者,另外本文的打包功能實現的比較粗糙,打包速度比較慢,若是看官有啥建議,請在評論下告知下我。

若是有錯誤的地方,還請指出。謝謝閱讀。

代碼地址 spa-webpack-demo

參考

babel官方文檔

Webpack4 +babel7 多入口配置詳細教程

相關文章
相關標籤/搜索