從零搭建webpack4 + vue + vue-rout + vuex項目架構(gòu)

配置前說明:確保已安裝node環(huán)境。

檢查是否安裝node環(huán)境:

  1、終端輸入node -v或node --version
  2、終端輸入npm -v或npm --version

一、配置前命令簡寫說明:

1、npm inpm install區(qū)別:
a)npm i是npm install縮寫。
b)用npm i安裝的模塊無法用npm uninstall刪除,用npm uninstall i才卸載掉。
c)npm i會幫助檢測與當(dāng)前node版本最匹配的npm包版本號,并匹配出來相互依賴的npm包應(yīng)該提升的版本號。
d)部分npm包在當(dāng)前node版本下無法使用,必須使用建議版本。
e)安裝報錯時intall肯定會出現(xiàn)npm-debug.log 文件,npm i不一定。
2、npm -Dnpm -S的區(qū)別:
a)-S就是--save的簡寫。
b)-D就是--save-dev 這樣安裝的包的名稱及版本號就會存在package.json的devDependencies這個里面,而--save會將包的名稱及版本號放在dependencies里面。

二、webpack基礎(chǔ)配置(開發(fā)環(huán)境):

命令運行前提:終端進(jìn)入項目目錄文件夾里,以下不再說明。
1、創(chuàng)建一個項目目錄demo,使用NPM初始化配置:
npm init
執(zhí)行后,會有一系列選項,可以按回車快速確認(rèn),完成后,會在demo目錄生成一個package.json文件。
2、使用NPM安裝webpack模塊、webpack-dev-server模塊和webpack-cli模塊:
npm install webpack --save-dev
npm install webpack-dev-server --save-dev
npm i -D webpack-cli
安裝成功后,在package.json中會多幾項配置:

"devDependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  }

3、在demo目錄下創(chuàng)建webpack.config.js并初始化內(nèi)容:

const config = {

};
module.exports = config;

4、在package.jsonscripts里增加一個快速啟動webpack-dev-server服務(wù)的腳本和打包腳本:

{
  //...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --config=webpack.config.js",
    "build": "webpack --progress --hide-modules"
  },
  //...
}

其中--config是指向webpack-dev-server讀取的配置文件路徑。
--open會執(zhí)行命令時自動在瀏覽器打開頁面,默認(rèn)地址是127.0.0.1:8080
IP和端口都是可以配置的,例如:

//...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --host 172.172.172.1 --port 8888 --open --config=webpack.config.js"
  },
  //...

這樣訪問地址就改為了172.172.172.1:8888
5、入口(Entry)出口(Output)

webpack配置中最重要也是必選的兩項是入口(Entry)和出口(Output)。
入口的作用是告訴webpack從哪里開始尋找依賴,并且編譯。
出口的作用是用來配置編譯后的文件存儲位置和文件名。

在demo目錄下新建一個空的main.js作為入口的文件,然后在webpack.config.js中進(jìn)行入口和出口的配置:

const path = require('path');

const config = {
  entry: {
    main: './main'
  },
  output: {
    path: path.join(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'main.js'
  }
};

entry中的main就是配置的單入口,webpack會從main.js文件開始工作。
output中path選項用來存放打包后文件的輸出目錄,是必填項。
publicPath指定資源文件引用的目錄,如果你的資源存放在CDN上,這里可以填CDN的網(wǎng)址。
filename用于指定輸出文件的名稱。
因此,這里配置的output意為打包后的文件會存儲為demo/dist/main.js,只要在html中引入即可。

在demo目錄下新建一個index.html作為項目的入口:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1 user-scalable=0">
    <title>Demo</title>
</head>
<body>
    <div id="app"></div>
    <script src="./dist/main.js"></script>
</body>
</html>

運行npm run build命令,后再執(zhí)行npm run dev即可啟動了一個空項目。
6、webpack加載器(Loaders):
webpack通過安裝不同的加載器(Loaders)可以對各種后綴名的文件進(jìn)行處理。
css-loaderstyle-loader,通過NPM安裝:
npm install css-loader --save-dev
npm install style-loader --save-dev
安裝完成后,在webpack.config.js文件里配置Loader,增加對.css文件的處理:

const path = require('path');

const config = {
  //...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          'css-loader',
          'style-loader'
        ]
      }
    ]
  }
};
module.exports = config;

在module對象的rules屬性中可以指定一系列的loaders,每一個loader都必須包含testuse兩個選項。這段配置的意思是說,當(dāng)webpack編譯過程中遇到require()import語句導(dǎo)入一個后綴名為.css的文件時,先將它通過css-loader轉(zhuǎn)換,然后繼續(xù)打包。
use選項的值可以是數(shù)組或字符串,如果是數(shù)組,它的編譯順序就是從后往前。

在demo目錄下新建一個style.css的文件,作為全局css樣式,并在main.js中導(dǎo)入:

//main.js
import './style.css';

7、webpack插件(Plugins):
通過NPM安裝extract-text-webpack-plugin插件:
npm install extract-text-webpack-plugin@next --save-dev
然后在webpack.config.js配置文件中導(dǎo)入插件,并改寫loader的配置和index.html:

const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');

const config = {
    //...
    module: {
        rules: [
            {
                test: /\.css$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" }
                ]
            }
        ]
    },
    plugins: [
        // 重命名提取后的css文件
        new ExtractTextPlugin('main.css')
    ]
};

module.exports = config;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1 user-scalable=0">
    <title>Demo</title>
    <link rel="stylesheet" href="./dist/main.css">
</head>
...

到此,基本的webpack配置就寫完了。webpack雖然看似復(fù)雜,但它只不過是一個js配置文件,只要搞清楚入口(Entry)出口(Output)加載器(Loaders)插件(Plugins)這四個概念,使用起來就不那么困惑了。

三、單文件組件和vue-loader:

一個.vue文件一般包含3部分,即<template><script><style>,如下所示:

//component.vue
<template>
  <div>
    <span>你好:{{ name }}</span>
  </div>
</template>
<script>
  export default {
    props: {
      name: {
        type: String,
        default: ''
      }
    }
  }
</script>
<style scoped>
  span {
    color: #f60;
  }
</style>

在component.vue文件中,<template></template>之間的代碼就是該組件的模板HTML,<style></style>之間的是css樣式,示例中的<style>標(biāo)簽使用了scoped屬性,表示當(dāng)前的css只在這個組件有效,如果不加,那么span的樣式會應(yīng)用到整個項目。

使用.vue文件需要先安裝vue-loader、vue-style-loader等加載器并做配置。因為要使用ES6語法,還需要安裝babel和babel-loader等加載器。使用NPM逐個安裝以下依賴:
npm install --save vue
npm install --save-dev vue-loader
npm install --save-dev vue-style-loader
npm install --save-dev vue-template-compiler
npm install --save-dev vue-hot-reload-api
npm install --save-dev babel
npm i babel-loader@7.1.5 -D
npm install --save-dev babel-core
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-runtime
安裝完成后,修改配置文件webpack.config.js來支持對.vue文件及ES6的解析:

// webpack.config.js
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

const config = {
    entry: {
        main: './main'
    },
    output: {
        path: path.join(__dirname, './dist'),
        publicPath: '/dist/',
        filename: 'main.js'
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        css: ExtractTextPlugin.extract({
                            use: 'css-loader',
                            fallback: 'vue-style-loader'
                        })
                    }
                }
            },
            {
                test: /\.js$/,
                use: [
                    {
                        loader: 'babel-loader'
                    }
                ],
                exclude: /node_module/
            },
            {
                test: /\.css$/,
                use: [
                    { loader: "style-loader" },
                    { loader: "css-loader" }
                ]
            }
        ]
    },
    plugins: [
        // 重命名提取后的css文件
        new ExtractTextPlugin('main.css'),
        new VueLoaderPlugin()
    ]
};

module.exports = config;

vue-loader在編譯.vue文件時,會對<template><script><style>分別處理,所以在vue-loader選項里多了一項options來進(jìn)一步對不同語言進(jìn)行配置。比如在對css進(jìn)行處理時,會先通過css-loader解析,然后把處理結(jié)果再交給vue-style-loader處理。

在demo目錄下新建一個名為.babelrc的文件,并寫入babel的配置,webpack會依賴此配置文件來使用babel編譯ES6代碼:

{
    "presets": ["es2015"],
    "plugins": ["transform-runtime"],
    "comments": false
}

配置好后,就可以使用.vue文件了。每個.vue文件就代表一個組件,組件之間可以相互依賴。

四、webpack用于生產(chǎn)環(huán)境:

1、先對webpack進(jìn)一步配置,來支持更多常用的功能:
通過NPM安裝url-loaderfile-loader來支持圖片、字體等文件:
npm install --save-dev url-loader
npm install --save-dev file-loader

// webpack.config.js
const config = {
  //...
  module: {
    rules: [
      //...
      {
        test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
        loader: 'url-loader?limit=1024'
      }
    ]
  }
};

當(dāng)遇到.gif.png.ttf等格式文件時,url-loader會把它們一起編譯到dist目錄下,"?limit=1024"是指如果這個文件小于1kb就以base64的形式加載,不會生成一個文件。
webpack.config.jsoutput選項里已經(jīng)指定了pathpubilcPath,打完包后,所有的資源都會保存在demo/dist目錄下。
2、為了方便開發(fā)和生產(chǎn)環(huán)境的切換,在demo目錄下再新建一個用于生產(chǎn)環(huán)境的配置文件webpack.prod.config.js
打包會用到下面兩個依賴,使用NPM安裝:
npm install --save-dev webpack-merge
npm install --save-dev html-webpack-plugin
package.json中,再加入一個probuild的快捷腳本用來打包:

{
  //...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --config=webpack.config.js",
    "build": "webpack --progress --hide-modules",
    "probuild": "webpack --mode production --progress --hide-modules --config=webpack.prod.config.js"
  },
  //...
}

webpack.prod.config.js代碼如下:

// webpack.prod.config.js
const webpack = require('webpack');
const HtmlwebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const merge = require('webpack-merge');
const webpackBaseConfig = require('./webpack.config.js');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

// 清空基本配置的插件列表
webpackBaseConfig.plugins = [];

module.exports = merge(webpackBaseConfig, {
    output: {
        publicPath: '/dist/',
        // 將入口文件重命名為帶有20位hash值得唯一文件
        filename: '[name].[hash].js'
    },
    // 定義當(dāng)前為生產(chǎn)環(huán)境
    mode: 'production',
    plugins: [
        new ExtractTextPlugin({
            filename: '[name].[hash].css',
            allChunks: true
        }),
        // 提取模板,并保留入口html文件
        new HtmlwebpackPlugin({
            filename: './index_prod.html',
            template: './index.html',
            minify: {
                //對 html 文件進(jìn)行壓縮,minify 的屬性值是一個壓縮選項或者 false 。默認(rèn)值為false, 不對生成的 html 文件進(jìn)行壓縮
                removeComments:true, // 去除注釋
                collapseWhitespace: true //是否去除空格
            }
        }),
        new VueLoaderPlugin()
    ],
    // 對js文件進(jìn)行壓縮
    optimization: {
        splitChunks: {
            chunks: 'all'
        },
        runtimeChunk: true
    }
})

上面安裝的webpack-merge模塊就是用于合并兩個webpack的配置文件,所以prod的配置是在webpack.config.js基礎(chǔ)上擴展的。
html-webpack-plugin是用來生成html文件的,它通過template選項來讀取指定的模板index.html,然后輸入到filename指定的目錄,就是demo/index_prod.html

五、vue-router配置:

1、在demo目錄下新建一個app.vue文件并寫入以下內(nèi)容:

<!-- app.vue -->
<template>
    <div>
        <router-view></router-view>
    </div>
</template>
<script>
    export default {
        name: 'app'
    }
</script>

app.vue里的路由視圖<router-view>掛載所有的路由組件。
運行網(wǎng)頁時,<router-view>會根據(jù)當(dāng)前路由動態(tài)渲染不同的頁面組件。路由切換時,切換的是<router-view>掛載的組件,其他的內(nèi)容并不會變化。
2、通過NPM安裝vue-router:
npm install --save vue-router
main.js里使用Vue.use()加載插件:

import './style.css';
//導(dǎo)入Vue框架
import Vue from 'vue';
//導(dǎo)入vue-router路由
import VueRouter from 'vue-router';
//導(dǎo)入app.vue組件
import App from './app.vue';

Vue.use(VueRouter);

//創(chuàng)建Vue根實例
new Vue({
  el: '#app',
  render: h => h(App)
});

每個頁面對應(yīng)一個組件,也就是對應(yīng)一個.vue文件。
3、在demo目錄下創(chuàng)建views文件夾,用于存放所有的頁面,然后在views創(chuàng)建index.vue文件并寫入以下內(nèi)容:

<!-- index.vue -->
<template>
    <div>
        <h1>首頁</h1>
    </div>
</template>
<script>
    export default {
        name: 'index'
    }
</script>

4、再回到main.js,完成路由的剩余配置。創(chuàng)建一個數(shù)組來制定路由匹配列表,每一個路由映射一個組件:

//main.js
const Routers = [
    {
        path: '/index',
        component: (resolve) => require(['./views/index.vue'], resolve)
    },
    // 當(dāng)訪問路徑不存在時,重定向到首頁
    {
        path: '*',
        redirect: '/index'
    }
]

Routers里每一項的path屬性就是指定當(dāng)前匹配的路徑,component是映射的組件。上例的寫法,webpack會把每一個路由都打包為一個js文件,在請求到該頁面時,才去加載這個頁面的js,也就是異步實現(xiàn)的懶加載(按需加載)。這樣做的好處是不需要在打開首頁的時候就把所有的頁面內(nèi)容全部加載進(jìn)來,只在訪問時才加載。
5、使用了異步路由后,編譯出的每個頁面的js都叫做chunk(塊),它們命名默認(rèn)是0.main.js、1.main.js......可以在webpack配置的出口output里通過設(shè)置chunkFilename字段修改chunk命名,例如:

//webpack.config.js
output: {
        path: path.join(__dirname, './dist'),
        publicPath: '/dist/',
        filename: '[name].js',
        chunkFilename: '[name].chunk.js'
    },

有了chunk后,在每個頁面(.vue文件)里寫的樣式也需要配置后才會打包進(jìn)main.css,配置插件:

//webpack.config.js
plugins: [
        // 重命名提取后的css文件
        new ExtractTextPlugin({
            filename: '[name].css',
            allChunks: true
        }),
        new VueLoaderPlugin()
    ]

6、繼續(xù)在main.js里完成配置和路由實例:

//main.js
const RouterConfig = {
    // 使用HTML5的History路由模式
    mode: 'history',
    routes: Routers
};
const router = new VueRouter(RouterConfig);

//創(chuàng)建Vue根實例
new Vue({
    el: '#app',
    router: router,
    render: h => h(App)
});

RouterConfig里,設(shè)置modehistory會開啟HTML5History路由模式,通過“/”設(shè)置路徑。如果不配置mode,就會使用“#”來設(shè)置路徑。開啟History路由,在生產(chǎn)環(huán)境時服務(wù)端必須進(jìn)行配置,將所有路由都指向同一個html或設(shè)置404頁面為該html,否則刷新時頁面會出現(xiàn)404。
7、webpack-dev-server也要配置下來支持History路由,在package.json中修改dev命令:

"scripts": {
    //...
    "dev": "webpack-dev-server --open --history-api-fallback --config=webpack.config.js",
    //...
  },

增加了--history-api-fallback,所有的路由都會指向index.html。

六、vuex配置:

1、通過NPM安裝Vuex:
npm install --save vuex
它的用法與vue-router類似,在main.js里,通過Vue.use()使用Vuex:

// main.js
import './style.css';
//導(dǎo)入Vue框架
import Vue from 'vue';
//導(dǎo)入vue-router路由
import VueRouter from 'vue-router';
//導(dǎo)入Vuex
import Vuex from 'vuex';
//導(dǎo)入app.vue組件
import App from './app.vue';

Vue.use(VueRouter);
Vue.use(Vuex);

//路由配置
//省略...

const store = new Vuex.Store({
    // vuex的配置
});

//創(chuàng)建Vue根實例
new Vue({
    el: '#app',
    router: router,
    // 使用vuex
    store: store,
    render: h => h(App)
});

倉庫store包含了應(yīng)用的數(shù)據(jù)(狀態(tài))和操作過程。Vuex里的數(shù)據(jù)都是響應(yīng)式的,任何組件使用同一store的數(shù)據(jù)時,只要store的數(shù)據(jù)變化,對應(yīng)的組件也會立即更新。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容