詳解從零搭建 vue2 vue-router2 webpack3 工程
以新手視角,詳細介紹各個步驟內(nèi)容,不深入講步驟涉及的原理,主要介紹如何操作。
初始化工程
新建工程目錄 vue2practice,在目錄下執(zhí)行npm init -y來創(chuàng)建一個 package.json,在 package.json 中先添加以下必備模塊:
{
"name": "vue2-vue-router2-webpack3",
"version": "1.0.0",
"devDependencies": {
"vue": "^2.4.2",
"vue-loader": "^13.0.2",
"vue-router": "^2.7.0",
"vue-template-compiler": "^2.4.2",
"webpack": "^3.4.1",
"webpack-dev-server": "^2.6.1"
}
}
其中 vue-template-compiler 是 vue-loader 的 peerDependencies,npm3 不會自動安裝 peerDependencies,然而 vue-template-compiler 又是必備的,那為什么作者不將其放到 dependencies 中呢?有人在 github 上提過這個問題,我大致翻譯一下作者的回答(僅供參考):這樣做的原因是因為沒有可靠的方式來固定嵌套依賴的關(guān)系,怎么理解這句話?首先 vue-template-compiler 和 vue 的版本號是一致的(目前是同步更新),將 vue-template-compiler 指定為 vue-loader 的 dependencies 并不能保證 vue-template-compiler 和 vue 的版本號是相同的,讓用戶自己指定版本才能保證這一點。查看作者的回答(英文) 。如果兩者版本不一致,運行時會出現(xiàn)下圖所示的錯誤提示。

新建目錄結(jié)構(gòu)如下,新增的目錄及文件先空著,后面的步驟會說明添加什么內(nèi)容。
vue2pratice
|-- package.json
|-- index.html // 啟動頁面
|-- webpack.config.js // webpack配置文件
|-- src
|-- views // vue頁面組件目錄
|-- main.js // 入口文件
|-- router.js // vue-router配置
|-- app.vue // 工程首頁組件
配置Webpack
Webpack 默認讀取 webpack.config.js,文件名不能隨便改,其中 entry 是必須配置的。
module.exports = {
entry: './src/main.js',
output: {
path: __dirname + '/dist',
publicPath: '/static/',
filename: 'build.js'
}
}
Webpack 2+ 要求output.path必須為絕對路徑。
配置 webpack-dev-server,只需在 package.json 添加以下啟動命令即可。
"scripts": {
"dev": "webpack-dev-server --hot --open"
}
webpack-dev-server 2 默認為 inline 模式,熱模塊替換仍需自己設(shè)置。
驗證配置
在 index.html 中添加測試代碼,引入打包后的 JS 文件。
<body> Hello, Webpack 3. <br> <script src="/static/build.js"></script> </body>
在 main.js 中添加測試代碼。
// main.js
document.write('來自main.js的問候!')
執(zhí)行下面的命令來安裝模塊并啟動服務(wù)器。
// 安裝依賴 npm install // 運行 npm run dev
啟動后瀏覽器會自動打開http://localhost:8080,如果控制臺沒有報錯,頁面正確顯示 main.js 和 index.html 的內(nèi)容,改動 main.js 后瀏覽器不刷新能看到效果,則表示配置沒問題。

Vue
新建頁面
在 views 目錄下新建 index.vue。
<template>
<div>
這是{{page}}頁面
</div>
</template>
<script>
export default {
data: function () {
return {
page: 'index'
}
}
}
</script>
webpack 1 需要特定的 loader 來轉(zhuǎn)換 ES 2015 import/export,webpack 2 起可以開箱即用。但是 ES6 的新語法還是需要 loader 來轉(zhuǎn)換,在沒有配置前,先不要用新語法。用了也沒報錯(比如 let,const等),那是因為你的瀏覽器已經(jīng)支持了 ES6 語法(新版本瀏覽器都已經(jīng)支持)。
配置路由
將 vue-router 實例化傳入的參數(shù)new VueRouter(參數(shù))提取到 router.js 形成路由配置文件。
import index from './views/index.vue'
export default {
routes: [
{
path: '/index',
component: index
}
]
}
從 vue-loader@13.0.0,不能用 require 來引入 .vue 文件,因為 .vue 文件最終會被編譯成 ES6 module。
首頁
首頁引入 ouput 配置的 JS,添加 Vue 實例的掛載目標。
<body> <div id="app"></div> <script src="/static/build.js"></script> </body>
入口JS完成路由配置、初始化 Vue 實例。
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './app.vue';
import routerConfig from './router';
Vue.use(VueRouter);
var router = new VueRouter(routerConfig)
new Vue({
el: '#app',
router: router,
render: h => h(App)
});
從 Vue 2.2.0 后使用 require('vue') 會報錯,應(yīng)使用 ES6 module(import),具體原因請參考 Vue 更新說明 https://github.com/vuejs/vue/releases,截圖如下:

在首頁組件 app.vue 中添加路由鏈接、路由視圖組件。
<template>
<div>
<div>
<router-link to="/index">Home</router-link>
</div>
<div>
<router-view></router-view>
</div>
</div>
</template>
配置loader
配置 vue 文件對應(yīng)的 loader。
module: {
rules: [
{
test: /\.vue$/,
use: ["vue-loader"]
}
]
}
Webpack2 必須在 module.rules 下配置 loader。'-loader'不能省略,必須將 loader 名寫全。可以使用 Rule.use 或 Rule.loader 來配置 loader(Rule.loader 是 Rule.use: [ { loader } ] 的簡寫),建議用 use。
上面完成了新增頁面及訪問該頁面所需的配置,下面來測試下是否能正常訪問/index。執(zhí)行npm run dev,瀏覽器顯示如圖界面。

支持CSS
安裝 css-loader 后即可在 vue 文件中使用
npm i css-loader -D
想要支持import / require引入CSS文件,則需要配置對應(yīng)的 Rule。
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"]
}
<script> import "../style/style.css" </script>
支持CSS預(yù)處理語言
以 stylus 為例,安裝 stylus 及 stylus-loader。
npm install stylus stylus-loader -D
增加 .styl 文件對應(yīng)的 loader 配置。
{
test: /\.styl$/,
use: ["vue-style-loader", "css-loader", "stylus-loader"]
}
使用示例:
<style lang="stylus">
.stylus
.red
color red
</style>
<script>
import "../css/stylus-example.styl"
</script>
node-sass 安裝慢的解決辦法

使用淘寶鏡像:
npm set disturl https://npm.taobao.org/dist
也可以單獨設(shè)置node-sass鏡像:
npm set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass
支持圖片及圖標字體
安裝圖片及圖標字體依賴的loader。
npm install url-loader file-loader -D
增加圖片及圖標字體的loader配置。
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]' // 將圖片都放入images文件夾下,[hash:7]防緩存
}
}]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]' // 將字體放入fonts文件夾下
}
}]
}
構(gòu)建
添加打包命令如下:
"build":"webpack --progress --colors"
執(zhí)行npm run build開始構(gòu)建,完成后,可以看到工程目錄下多了dist目錄以及 dist/build.js。
使用 Webpack 插件
壓縮JS
在之前的文章提到過,打開未壓縮版的build.js,你會發(fā)現(xiàn)ES6的語法沒有被轉(zhuǎn)化為ES5,因此需要安裝babel 套件來完成語法的轉(zhuǎn)化,否則壓縮的時候就會報錯。之前廣泛使用的轉(zhuǎn)碼規(guī)則為 babel-preset-es2015,但 Babel 的官網(wǎng)上在9月宣布 ES2015 / ES2016/ ES2017 等等 ES20xx 時代的 presets 通通被廢棄(deprecated),取而代之的是 babel-preset-env,并且承諾它將成為“未來不會過時的(future-proof)”解決方案。
npm i babel-loader babel-core babel-preset-env -D
增加babel的配置文件.babelrc。
{
"presets": [
["env", { "modules": false }]
],
"comments": false
}
將 modules 設(shè)置為 false,即交由 Webpack 來處理模塊化,通過其 TreeShaking 特性將有效減少打包出來的 JS 文件大小,可以自行對比下前后打包出來的文件的大小,效果還是不錯的。
comments 即是否保留注釋。
接著配置 JS 文件的 loader。
{
test: /\.js$/,
use: "babel-loader",
include: [path.resolve(__dirname, 'src')]
}
注意:Webpack2建議盡量避免exclude,更傾向于使用include。
壓縮 JS 采用webpack.optimize.UglifyJsPlugin,配置如下:
new webpack.optimize.UglifyJsPlugin()
官網(wǎng)稱warnings默認為false,你可能會遇到即使沒有配置warnings: true,控制臺仍顯示警告,看下面這段源碼就知道了。查看源碼

只有當options.compress !== false時 warnings 才會被設(shè)置默認值 false,所以一旦配置了 compress 其它選項,那就需同時配置warnings: false。
warnings作用是當插件在壓縮過程中移除的無效代碼或定義是顯示警告信息(display warnings when dropping unreachable code or unused declarations etc.)。
提取CSS
使用extract-text-webpack-plugin插件提取CSS。更改 css 及 less 的 loader 配置如下。
// 安裝插件 npm i extract-text-webpack-plugin -D
// var ExtractTextPlugin = require("extract-text-webpack-plugin")
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: "css-loader"
})
},
{
test: /\.styl$/,
use: ExtractTextPlugin.extract({
use: ["css-loader", "stylus-loader"]
})
}
上述配置并不能提取 vue 文件中的 style,需要設(shè)置 vue-loader 參數(shù)才可以。
{
test: /\.vue$/,
use: {
loader: "vue-loader",
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader'
}),
stylus: ExtractTextPlugin.extract({
use: ["css-loader", "stylus-loader"]
})
}
}
}
}
初始化插件,filename 可以指定 CSS 文件的目錄。
new ExtractTextPlugin({
filename: "css/style.css"
})
PostCSS
安裝 postcss-loader 及 postcss 插件。
npm i postcss-loader cssnano -D
配置 loader 如下:
// css-loader配置改為 use: ['css-loader', "postcss-loader"] // stylus-loader配置改為 use: ["css-loader", "postcss-loader", "stylus-loader"]
postcss-loader 要放在 css-loader 和 style-loader 之后,CSS 預(yù)處理語言 loader 之前(stylus-loader)。
新增 postcss.config.js 來配置postcss插件,這樣就不用給每個 postcss-loader 去配置。更多 postcss-loader 的配置方式請參考 postcss-load-config。
module.exports = {
plugins: [
require('cssnano')
]
}
cssnano 使用了一系列 postcss 插件,包含了常用的 autoprefixer 等,如何傳入 autoprefixer 的配置?
require('cssnano')({
autoprefixer: {
add: true,
browsers: ['> 5%']
}
})
其中有一個插件 postcss-zindex 使用中發(fā)現(xiàn)有些問題。如果想禁用這個插件的話,配置如下:
require('cssnano')({
zindex: {
disable:true
}
})
附:postcss插件分類搜索網(wǎng)站:http://postcss.parts/
生成首頁
安裝 html-webpack-plugin 插件。
npm i html-webpack-plugin -D
初始化插件。
// var HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.tpl.html'
})
其它插件
Webpack3 新增的作用域提升。
new webpack.optimize.ModuleConcatenationPlugin()
指定生產(chǎn)環(huán)境,以便在壓縮時可以讓 UglifyJS 自動刪除代碼塊內(nèi)的警告語句。
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
因為這個插件直接做的文本替換,給定的值必須包含字符串本身內(nèi)的實際引號。通常,有兩種方式來達到這個效果,使用 '"production"', 或者使用 JSON.stringify('production')。
你完全可以在自己的代碼中使用process.env.NODE_ENV來區(qū)分開發(fā)和生產(chǎn),從而針對不同的環(huán)境做一些事情。不用擔(dān)心這部分代碼會被保留,最終會被 UglifyJS 刪除。例如:
if (process.env.NODE_ENV != "production") {
// 開發(fā)環(huán)境
}
// webpack.DefinePlugin插件替換后,上述代碼會變成
if ("production" != "production") {
// 開發(fā)環(huán)境
}
// 輸出
if (false) {
// 開發(fā)環(huán)境
}
// UglifyJS 會刪除這段無效代碼
使用上述插件后再次構(gòu)建,會發(fā)現(xiàn)生成的JS相比原來的體積小了不少。
friendly-errors-webpack-plugin 是一個更友好顯示 webpack 錯誤信息的插件。插件 github 地址:https://github.com/geowarin/friendly-errors-webpack-plugin
一般在開發(fā)環(huán)境下使用。
var FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');
var webpackConfig = {
// ...
plugins: [
new FriendlyErrorsWebpackPlugin(),
],
// ...
}
效果如下圖:

顯示構(gòu)建進度插件:webpack.ProgressPlugin
{
// ...
plugins: [
new webpack.ProgressPlugin(),
],
// ...
}
效果如下圖:

美化 webpack 編譯控制臺打印的信息的插件webpack-dashboard

分離Webpack配置
將開發(fā)和生產(chǎn)配置文件分離,方便增加各個環(huán)境下的個性配置。Webpack2文檔中也詳細闡述了如何為多環(huán)境配置webpack?;舅悸啡缦拢?/p>
- 編寫一個基本配置文件(webpack.base.config.js)
- 使用webpack-merge合并這個基礎(chǔ)配置和針對環(huán)境的特定的配置(webpack.dev.config.js,webpack.prod.config.js)
webpack.base.config.js 內(nèi)容如下:
var webpack = require('webpack');
var path = require('path');
var utils = require('./utils');
function resolve(relPath) {
return path.resolve(__dirname, relPath);
}
module.exports = {
entry: { app: resolve('../src/main.js') },
output: {
filename: 'js/[name].js'
},
module: {
rules: [{
test: /\.js$/,
use: "babel-loader",
include: [resolve('../src')]
},
{
test: /\.vue$/,
use: {
loader: "vue-loader",
options: utils.vueLoaderOptions()
}
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: {
loader: "url-loader",
options: {
limit: 10000,
name: 'images/[name].[hash:7].[ext]'
}
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [{
loader: "url-loader",
options: {
limit: 10000,
name: 'fonts/[name].[hash:7].[ext]'
}
}]
}
]
}
}
為什么要將vue-loader的options提取出來?其主要是用來配置CSS及CSS預(yù)處理語言的loader,開發(fā)環(huán)境可以不用配置,但是生產(chǎn)環(huán)境需要提取CSS、增加postcss-loader等,因此需要提取出來針對不同環(huán)境返回相應(yīng)的options。后面會列出utils.vueLoaderOptions的內(nèi)容。
為什么沒有配置CSS的loader?理由和上面的vue-loader一樣。
為什么沒有配置path和publicPath?一方面是個性化參數(shù),另外開發(fā)和生產(chǎn)可能不相同,因此在webpack.dev.config和webpack.prod.config中分別配置更為合適。
webpack.dev.config.js 內(nèi)容如下:
var webpack = require('webpack');
var merge = require('webpack-merge');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var baseWebpackConfig = require('./webpack.base.config');
var utils = require('./utils');
var config = require('./config');
Object.keys(baseWebpackConfig.entry).forEach(function(name) {
baseWebpackConfig.entry[name] = [
`webpack-dev-server/client?http://localhost:${config.dev.port}/`,
"webpack/hot/dev-server"
].concat(baseWebpackConfig.entry[name])
});
module.exports = merge(baseWebpackConfig, {
output: {
path: config.dev.outputPath,
publicPath: config.dev.outputPublicPath
},
module: {
rules: utils.styleLoaders()
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
})
添加了HtmlWebpackPlugin后,index.html中就不需要在自己去引用打包的JS了,會自動根據(jù)打包的JS添加引用,這樣更加方便,關(guān)于HtmlWebpackPlugin的配置,需要說明兩點:
1.template的路徑是相對于webpack編譯時的上下文目錄,說白了就是項目根目錄,因此上面可以直接配置index.html,其指向的就是根目錄下的index.html;
2.filename則是相對于webpack配置項output.path(打包資源存儲路徑)。
html-webpack-plugin關(guān)于template和filename路徑源碼如下:
// https://github.com/jantimon/html-webpack-plugin/blob/master/index.js // template this.options.template = this.getFullTemplatePath(this.options.template, compiler.context); // filename this.options.filename = path.relative(compiler.options.output.path, filename);
config.js內(nèi)容如下:
module.exports = {
dev: {
outputPath: path.resolve(__dirname, '../static'),
outputPublicPath: '/',
port: 8000
},
prod: {
outputPath: path.resolve(__dirname, '../static'),
outputPublicPath: '/static/'
}
}
utils.js內(nèi)容如下:
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var isProd = process.env.NODE_ENV === "production";
// 根據(jù)項目需求添加CSS預(yù)處理語言并安裝相應(yīng)的loader,以stylus-loader為例
var cssLang = [{
name: 'css',
reg: /\.css$/,
loader: 'css-loader'
}, {
name: 'stylus',
reg: /\.styl$/,
loader: "stylus-loader"
}];
function genLoaders(lang) {
var loaders = ['css-loader', 'postcss-loader'];
if (lang.name !== 'css') {
loaders.push(lang.loader);
}
if (isProd) {
// 生產(chǎn)環(huán)境需要提取CSS
loaders = ExtractTextPlugin.extract({
use: loaders
});
} else {
// 開發(fā)環(huán)境需要vue-style-loader將CSS提取到頁面頭部
loaders.unshift('vue-style-loader');
}
return loaders;
}
// 各種CSS的loader
exports.styleLoaders = function() {
var output = [];
cssLang.forEach(lang => {
output.push({
test: lang.reg,
use: genLoaders(lang)
})
})
return output;
};
// vue-loader的options
exports.vueLoaderOptions = function() {
var options = {
loaders: {}
};
cssLang.forEach(lang => {
options.loaders[lang.name] = genLoaders(lang);
});
return options;
}
接下來就是如何啟動webpack-dev-server,vue-cli的webpack模板工程用的express及webpack中間件做開發(fā)服務(wù)器,其實用webpack-dev-server就能滿足需求,當然用express能夠做更多的事情,畢竟webpack-dev-server是一個輕量級的express。dev.js內(nèi)容如下:
var webpack = require('webpack');
var webpackDevServer = require('webpack-dev-server');
var devConfig = require("./webpack.dev.config");
var config = require("./config");
var compiler = webpack(devConfig);
var server = new webpackDevServer(compiler, {
hot: true,
noInfo: true,
publicPath: config.dev.outputPublicPath,
stats: { colors: true }
});
server.listen(config.dev.port, "0.0.0.0");
var url = `http://localhost:${config.dev.port}/`;
// 需先安裝 opn 模塊 npm i opn -D
var opn = require('opn');
// 打包完畢后啟動瀏覽器
server.middleware.waitUntilValid(function() {
console.log(`> Listening at ${url}`);
opn(`${url}`);
})
生產(chǎn)配置文件(webpack.prod.config.js)內(nèi)容如下:
// 設(shè)定為生產(chǎn)環(huán)境
process.env.NODE_ENV = 'production';
var webpack = require('webpack');
var merge = require('webpack-merge');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var baseWebpackConfig = require('./webpack.base.config');
var utils = require('./utils');
var config = require('./config');
module.exports = merge(baseWebpackConfig, {
output: {
path: config.prod.outputPath,
publicPath: config.prod.outputPublicPath
},
module: {
rules: utils.styleLoaders()
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin({
filename: "css/style.css?[contenthash:8]"
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
})
生產(chǎn)構(gòu)建(prod.js)內(nèi)容如下:
var webpack = require("webpack");
var webpackProdConfig = require('./webpack.prod.config');
webpack(webpackProdConfig, function(err, stats) {
process.stdout.write(stats.toString());
});
對應(yīng)在package.json中添加開發(fā)和生產(chǎn)構(gòu)建的命令如下:
"scripts": {
"dev": "node build/dev.js",
"build": "node build/prod.js"
}
代碼分割
參照vue-cli及webpack文檔的提取公共代碼的方式,利用插件webpack.optimize.CommonsChunkPlugin將來自node_modules下的模塊提取到vendor.js(一般來講都是外部庫,短時間不會發(fā)生變化)。于是有如下代碼:
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function(module, count) {
return module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0
}
})
如果你查看未壓縮版的vendor.js,會發(fā)現(xiàn)不僅包含vue的代碼,還包含了webpackBootstrap(webpack模塊加載器)的代碼,按理說放在vendor里面也沒啥問題,畢竟后面的模塊都需要依賴于此,但是如果你的chunk使用了hash,一旦app代碼發(fā)生了改變,相應(yīng)的hash值會發(fā)生變化,webpackBootstrap的代碼也會發(fā)生變化(如圖),而我們提取vendor的初心就是這部分代碼改變頻率不大,顯然這不符合我們的目標,那么應(yīng)當將webpackBootstrap再提取到一個文件中,代碼如下:
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
})
用 import 還是 require
vue 2.2.0 后不能直接使用 require 來加載 vue,那么到底改是該使用 ES6 Module 還是 CommonJS 呢?,先看一個對比圖:
全部使用 ES6 Module,即import、export default,最終打包的app.js為1.20KB。

全部使用 CommonJS(除了vue),即require、module.exports,最終打包的app.js為1.12KB。

雖然兩者大小相差不大,但是這不禁讓人覺得用 CommonJS 似乎是一條優(yōu)化措施,那么代碼層面到底是怎么回事呢?
為了一探究竟,注釋了壓縮插件,以about.vue最終構(gòu)建的代碼來看,使用 CommonJS 的代碼如下:
(function (module, exports, __webpack_require__) {
"use strict";
module.exports = {
data: function data() {
return {
page: 'about'
};
}
};
}),
這基本上和 about.vue 中的代碼相差無幾,而使用 ES6 Module 構(gòu)建的代碼如下:
(function (module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = {
data: function data() {
return {
page: 'about'
};
}
};
}),
對比兩種規(guī)范下構(gòu)建后的代碼,使用 ES6 Module 主要是多了 Object.defineProperty 那一部分,從而導(dǎo)致了最終打包的文件大一點兒。那是不是為了最終文件體積能小些就全部使用 CommonJS 呢?這個需要你充分理解 CommonJS 和 ES6 Module 的區(qū)別,引用《ECMAScript 6入門》這本書的解釋如下:
ES6模塊加載的機制,與CommonJS模塊完全不同。CommonJS模塊輸出的是一個值的拷貝,而ES6模塊輸出的是值的引用。
為了更清楚的理解這段話,我們稍微做一下測試,在 src 下增加一個test.js,內(nèi)容如下(分別將兩種寫法列出):
// CommonJS
var counter = 1;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
// ES6 Module
export let counter = 1;
export function incCounter() {
counter++;
}
在about.vue中測試如下:
// CommonJS
var test = require('../test');
export default {
created() {
console.log(test.counter); // 1
test.incCounter();
console.log(test.counter); // 1
}
}
// ES6 Module
import { counter, incCounter } from '../test';
export default {
created() {
console.log(counter); // 1
incCounter();
console.log(counter); // 2
}
}
最終的輸出值也印證了前面的解釋,更詳細的解讀請查閱相關(guān)資料或書籍。只有深入理解了兩者的區(qū)別,自然就能明白何時該使用何種規(guī)范。當然 ES6 作為未來的趨勢,我們應(yīng)該去做更多的嘗試。
異步組件(懶加載)
之前用懶加載的方式是:require.ensure,在 webpack2 中引入了 Code Splitting-Async 的新方法 import(),用于動態(tài)引入 ES Module。require.ensure 可以指定 chunkFilename,但是 import 沒有很好的途徑去指定,webpack3 為了解決這個問題,提出了用魔法注釋的方式來指定模塊名。
結(jié)合 vue-router 可以輕松實現(xiàn)懶加載,配置路由指向異步組件即可實現(xiàn)懶加載,比如:
{
path: '/async',
component: () => import(/* webpackChunkName: "async" */'./views/async.vue')
}
如果你發(fā)現(xiàn)使用 import() 運行時報錯,有幾種情況:
1.babel presets 配置為 es2015,則不支持動態(tài)導(dǎo)入功能,因此需要安裝支持動態(tài)導(dǎo)入的 presets(npm i babel-preset-stage-2 -D),或者 babel 插件(npm i babel-plugin-syntax-dynamic-import -D);
2.babel presets 配置為 env,但是 modules 配置為 false,babel 則不會解析 import,可以安裝插件 (npm i babel-plugin-syntax-dynamic-import -D)解決。
魔法注釋雖然指定了塊名,但是 webpack 默認的塊名配置為 [id].js,即用的模塊的 id 作為塊名,因此需要我們手動改下配置。
修改 webpack.base.config.js 的 output:
output: {
filename: 'js/[name].js',
chunkFilename: "js/[name].[chunkhash].js"
}
效果如下圖:
如果發(fā)現(xiàn)魔法注釋沒有生效,要檢查下 .babelrc 的配置項 comments 是否設(shè)為 true?;蛘卟慌渲?comments(默認為true)
extract-text-webpack-plugin 默認不會提取異步模塊中的 CSS,需要加上配置:
new ExtractTextPlugin({
allChunks:true,
filename: "css/style.css?[contenthash:8]"
})
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
適用于 Vue 的播放器組件Vue-Video-Player操作
這篇文章主要介紹了適用于 Vue 的播放器組件Vue-Video-Player操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-11-11
vue自定義密碼輸入框解決瀏覽器自動填充密碼的問題(最新方法)
這篇文章主要介紹了vue自定義密碼輸入框解決瀏覽器自動填充密碼的問題,通過將密碼輸入框的type設(shè)置為text,修改樣式上的顯示,來實現(xiàn)既可以讓瀏覽器不自動填充密碼,又可以隱藏密碼的效果,需要的朋友可以參考下2023-04-04
如何用vue2+element-ui實現(xiàn)多行行內(nèi)表格編輯
最近開發(fā)項目,關(guān)于表格的數(shù)據(jù)操作比較多,這個地方個人覺得比較難搞,特此記錄一下,這篇文章主要給大家介紹了關(guān)于如何用vue2+element-ui實現(xiàn)多行行內(nèi)表格編輯的相關(guān)資料,需要的朋友可以參考下2024-08-08

