国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 編程 > JavaScript > 正文

詳解從零搭建 vue2 vue-router2 webpack3 工程

2019-11-19 14:53:04
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

以新手視角,詳細(xì)介紹各個(gè)步驟內(nèi)容,不深入講步驟涉及的原理,主要介紹如何操作。

初始化工程

新建工程目錄 vue2practice,在目錄下執(zhí)行npm init -y來(lái)創(chuàng)建一個(gè) 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 不會(huì)自動(dòng)安裝 peerDependencies,然而 vue-template-compiler 又是必備的,那為什么作者不將其放到 dependencies 中呢?有人在 github 上提過(guò)這個(gè)問(wèn)題,我大致翻譯一下作者的回答(僅供參考):這樣做的原因是因?yàn)闆](méi)有可靠的方式來(lái)固定嵌套依賴的關(guān)系,怎么理解這句話?首先 vue-template-compiler 和 vue 的版本號(hào)是一致的(目前是同步更新),將 vue-template-compiler 指定為 vue-loader 的 dependencies 并不能保證 vue-template-compiler 和 vue 的版本號(hào)是相同的,讓用戶自己指定版本才能保證這一點(diǎn)。查看作者的回答(英文) 。如果兩者版本不一致,運(yùn)行時(shí)會(huì)出現(xiàn)下圖所示的錯(cuò)誤提示。

新建目錄結(jié)構(gòu)如下,新增的目錄及文件先空著,后面的步驟會(huì)說(shuō)明添加什么內(nèi)容。

vue2pratice  |-- package.json  |-- index.html     // 啟動(dòng)頁(yè)面  |-- webpack.config.js // webpack配置文件  |-- src    |-- views    // vue頁(yè)面組件目錄    |-- main.js   // 入口文件    |-- router.js  // vue-router配置    |-- app.vue   // 工程首頁(yè)組件 

配置Webpack

Webpack 默認(rèn)讀取 webpack.config.js,文件名不能隨便改,其中 entry 是必須配置的。

module.exports = {  entry: './src/main.js',  output: {    path: __dirname + '/dist',    publicPath: '/static/',    filename: 'build.js'  }} 

Webpack 2+ 要求output.path必須為絕對(duì)路徑。

配置 webpack-dev-server,只需在 package.json 添加以下啟動(dòng)命令即可。

"scripts": { "dev": "webpack-dev-server --hot --open"} 

webpack-dev-server 2 默認(rèn)為 inline 模式,熱模塊替換仍需自己設(shè)置。

驗(yàn)證配置

在 index.html 中添加測(cè)試代碼,引入打包后的 JS 文件。

<body>  Hello, Webpack 3.  <br>  <script src="/static/build.js"></script></body> 

在 main.js 中添加測(cè)試代碼。

// main.jsdocument.write('來(lái)自main.js的問(wèn)候!') 

執(zhí)行下面的命令來(lái)安裝模塊并啟動(dòng)服務(wù)器。

// 安裝依賴npm install // 運(yùn)行npm run dev 

啟動(dòng)后瀏覽器會(huì)自動(dòng)打開(kāi)http://localhost:8080,如果控制臺(tái)沒(méi)有報(bào)錯(cuò),頁(yè)面正確顯示 main.js 和 index.html 的內(nèi)容,改動(dòng) main.js 后瀏覽器不刷新能看到效果,則表示配置沒(méi)問(wèn)題。

Vue

新建頁(yè)面

在 views 目錄下新建 index.vue。

<template>  <div>    這是{{page}}頁(yè)面  </div></template><script>export default {  data: function () {    return {      page: 'index'    }  }}</script> 

webpack 1 需要特定的 loader 來(lái)轉(zhuǎn)換 ES 2015 import/export,webpack 2 起可以開(kāi)箱即用。但是 ES6 的新語(yǔ)法還是需要 loader 來(lái)轉(zhuǎn)換,在沒(méi)有配置前,先不要用新語(yǔ)法。用了也沒(méi)報(bào)錯(cuò)(比如 let,const等),那是因?yàn)槟愕臑g覽器已經(jīng)支持了 ES6 語(yǔ)法(新版本瀏覽器都已經(jīng)支持)。

配置路由

將 vue-router 實(shí)例化傳入的參數(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 來(lái)引入 .vue 文件,因?yàn)?.vue 文件最終會(huì)被編譯成 ES6 module。

首頁(yè)

首頁(yè)引入 ouput 配置的 JS,添加 Vue 實(shí)例的掛載目標(biāo)。

<body><div id="app"></div><script src="/static/build.js"></script></body> 

入口JS完成路由配置、初始化 Vue 實(shí)例。

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') 會(huì)報(bào)錯(cuò),應(yīng)使用 ES6 module(import),具體原因請(qǐng)參考 Vue 更新說(shuō)明 https://github.com/vuejs/vue/releases,截圖如下:

在首頁(yè)組件 app.vue 中添加路由鏈接、路由視圖組件。

<template>  <div>    <div>      <router-link to="/index">Home</router-link>    </div>    <div>      <router-view></router-view>    </div>  </div></template> 

配置loader

配置 vue 文件對(duì)應(yīng)的 loader。

module: {  rules: [    {      test: //.vue$/,      use: ["vue-loader"]    }  ]} 

Webpack2 必須在 module.rules 下配置 loader。'-loader'不能省略,必須將 loader 名寫全。可以使用 Rule.use 或 Rule.loader 來(lái)配置 loader(Rule.loader 是 Rule.use: [ { loader } ] 的簡(jiǎn)寫),建議用 use。

上面完成了新增頁(yè)面及訪問(wèn)該頁(yè)面所需的配置,下面來(lái)測(cè)試下是否能正常訪問(wèn)/index。執(zhí)行npm run dev,瀏覽器顯示如圖界面。

支持CSS

安裝 css-loader 后即可在 vue 文件中使用

npm i css-loader -D 

想要支持import / require引入CSS文件,則需要配置對(duì)應(yīng)的 Rule。

{  test: //.css$/,  use: ["vue-style-loader", "css-loader"]} 
<script>import "../style/style.css"</script> 

支持CSS預(yù)處理語(yǔ)言

以 stylus 為例,安裝 stylus 及 stylus-loader。

npm install stylus stylus-loader -D 

增加 .styl 文件對(duì)應(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

也可以單獨(dú)設(shè)置node-sass鏡像:

npm set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass

支持圖片及圖標(biāo)字體

安裝圖片及圖標(biāo)字體依賴的loader。

npm install url-loader file-loader -D 

增加圖片及圖標(biāo)字體的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開(kāi)始構(gòu)建,完成后,可以看到工程目錄下多了dist目錄以及 dist/build.js。 

使用 Webpack 插件

壓縮JS

在之前的文章提到過(guò),打開(kāi)未壓縮版的build.js,你會(huì)發(fā)現(xiàn)ES6的語(yǔ)法沒(méi)有被轉(zhuǎn)化為ES5,因此需要安裝babel 套件來(lái)完成語(yǔ)法的轉(zhuǎn)化,否則壓縮的時(shí)候就會(huì)報(bào)錯(cuò)。之前廣泛使用的轉(zhuǎn)碼規(guī)則為 babel-preset-es2015,但 Babel 的官網(wǎng)上在9月宣布 ES2015 / ES2016/ ES2017 等等 ES20xx 時(shí)代的 presets 通通被廢棄(deprecated),取而代之的是 babel-preset-env,并且承諾它將成為“未來(lái)不會(huì)過(guò)時(shí)的(future-proof)”解決方案。

npm i babel-loader babel-core babel-preset-env -D 

增加babel的配置文件.babelrc。

{  "presets": [    ["env", { "modules": false }]  ],  "comments": false} 

將 modules 設(shè)置為 false,即交由 Webpack 來(lái)處理模塊化,通過(guò)其 TreeShaking 特性將有效減少打包出來(lái)的 JS 文件大小,可以自行對(duì)比下前后打包出來(lái)的文件的大小,效果還是不錯(cuò)的。

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默認(rèn)為false,你可能會(huì)遇到即使沒(méi)有配置warnings: true,控制臺(tái)仍顯示警告,看下面這段源碼就知道了。查看源碼

只有當(dāng)options.compress !== false時(shí) warnings 才會(huì)被設(shè)置默認(rèn)值 false,所以一旦配置了 compress 其它選項(xiàng),那就需同時(shí)配置warnings: false。

warnings作用是當(dāng)插件在壓縮過(guò)程中移除的無(wú)效代碼或定義是顯示警告信息(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ù)處理語(yǔ)言 loader 之前(stylus-loader)。

新增 postcss.config.js 來(lái)配置postcss插件,這樣就不用給每個(gè) postcss-loader 去配置。更多 postcss-loader 的配置方式請(qǐng)參考 postcss-load-config

module.exports = {  plugins: [    require('cssnano')  ]} 

cssnano 使用了一系列 postcss 插件,包含了常用的 autoprefixer 等,如何傳入 autoprefixer 的配置?

require('cssnano')({  autoprefixer: {    add: true,    browsers: ['> 5%']  }}) 

其中有一個(gè)插件 postcss-zindex 使用中發(fā)現(xiàn)有些問(wèn)題。如果想禁用這個(gè)插件的話,配置如下:

require('cssnano')({  zindex: {    disable:true  }}) 

附:postcss插件分類搜索網(wǎng)站:http://postcss.parts/

生成首頁(yè)

安裝 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)境,以便在壓縮時(shí)可以讓 UglifyJS 自動(dòng)刪除代碼塊內(nèi)的警告語(yǔ)句。

new webpack.DefinePlugin({  'process.env.NODE_ENV': JSON.stringify('production')}) 

因?yàn)檫@個(gè)插件直接做的文本替換,給定的值必須包含字符串本身內(nèi)的實(shí)際引號(hào)。通常,有兩種方式來(lái)達(dá)到這個(gè)效果,使用 '"production"', 或者使用 JSON.stringify('production')。

你完全可以在自己的代碼中使用process.env.NODE_ENV來(lái)區(qū)分開(kāi)發(fā)和生產(chǎn),從而針對(duì)不同的環(huán)境做一些事情。不用擔(dān)心這部分代碼會(huì)被保留,最終會(huì)被 UglifyJS 刪除。例如:

if (process.env.NODE_ENV != "production") {  // 開(kāi)發(fā)環(huán)境}// webpack.DefinePlugin插件替換后,上述代碼會(huì)變成if ("production" != "production") {  // 開(kāi)發(fā)環(huán)境}// 輸出if (false) {  // 開(kāi)發(fā)環(huán)境}// UglifyJS 會(huì)刪除這段無(wú)效代碼 

使用上述插件后再次構(gòu)建,會(huì)發(fā)現(xiàn)生成的JS相比原來(lái)的體積小了不少。

friendly-errors-webpack-plugin 是一個(gè)更友好顯示 webpack 錯(cuò)誤信息的插件。插件 github 地址:https://github.com/geowarin/friendly-errors-webpack-plugin

一般在開(kāi)發(fā)環(huán)境下使用。

var FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin'); var webpackConfig = { // ... plugins: [  new FriendlyErrorsWebpackPlugin(), ], // ...} 

效果如下圖:

顯示構(gòu)建進(jìn)度插件:webpack.ProgressPlugin

{ // ... plugins: [  new webpack.ProgressPlugin(), ], // ...} 

效果如下圖:

美化 webpack 編譯控制臺(tái)打印的信息的插件webpack-dashboard

分離Webpack配置

將開(kāi)發(fā)和生產(chǎn)配置文件分離,方便增加各個(gè)環(huán)境下的個(gè)性配置。Webpack2文檔中也詳細(xì)闡述了如何為多環(huán)境配置webpack。基本思路如下:

  1. 編寫一個(gè)基本配置文件(webpack.base.config.js)
  2. 使用webpack-merge合并這個(gè)基礎(chǔ)配置和針對(duì)環(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提取出來(lái)?其主要是用來(lái)配置CSS及CSS預(yù)處理語(yǔ)言的loader,開(kāi)發(fā)環(huán)境可以不用配置,但是生產(chǎn)環(huán)境需要提取CSS、增加postcss-loader等,因此需要提取出來(lái)針對(duì)不同環(huán)境返回相應(yīng)的options。后面會(huì)列出utils.vueLoaderOptions的內(nèi)容。

為什么沒(méi)有配置CSS的loader?理由和上面的vue-loader一樣。

為什么沒(méi)有配置path和publicPath?一方面是個(gè)性化參數(shù),另外開(kāi)發(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了,會(huì)自動(dòng)根據(jù)打包的JS添加引用,這樣更加方便,關(guān)于HtmlWebpackPlugin的配置,需要說(shuō)明兩點(diǎn):

1.template的路徑是相對(duì)于webpack編譯時(shí)的上下文目錄,說(shuō)白了就是項(xiàng)目根目錄,因此上面可以直接配置index.html,其指向的就是根目錄下的index.html;

2.filename則是相對(duì)于webpack配置項(xiàng)output.path(打包資源存儲(chǔ)路徑)。

html-webpack-plugin關(guān)于template和filename路徑源碼如下:

// https://github.com/jantimon/html-webpack-plugin/blob/master/index.js// templatethis.options.template = this.getFullTemplatePath(this.options.template, compiler.context);// filenamethis.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ù)項(xiàng)目需求添加CSS預(yù)處理語(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 {    // 開(kāi)發(fā)環(huán)境需要vue-style-loader將CSS提取到頁(yè)面頭部    loaders.unshift('vue-style-loader');  }  return loaders;}// 各種CSS的loaderexports.styleLoaders = function() {  var output = [];  cssLang.forEach(lang => {    output.push({      test: lang.reg,      use: genLoaders(lang)    })  })  return output;};// vue-loader的optionsexports.vueLoaderOptions = function() {  var options = {    loaders: {}  };  cssLang.forEach(lang => {    options.loaders[lang.name] = genLoaders(lang);  });  return options;} 

接下來(lái)就是如何啟動(dòng)webpack-dev-server,vue-cli的webpack模板工程用的express及webpack中間件做開(kāi)發(fā)服務(wù)器,其實(shí)用webpack-dev-server就能滿足需求,當(dāng)然用express能夠做更多的事情,畢竟webpack-dev-server是一個(gè)輕量級(jí)的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 -Dvar opn = require('opn');// 打包完畢后啟動(dòng)瀏覽器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());}); 

對(duì)應(yīng)在package.json中添加開(kāi)發(fā)和生產(chǎn)構(gòu)建的命令如下:

"scripts": {  "dev": "node build/dev.js",  "build": "node build/prod.js"} 

代碼分割

參照vue-cli及webpack文檔的提取公共代碼的方式,利用插件webpack.optimize.CommonsChunkPlugin將來(lái)自node_modules下的模塊提取到vendor.js(一般來(lái)講都是外部庫(kù),短時(shí)間不會(huì)發(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,會(huì)發(fā)現(xiàn)不僅包含vue的代碼,還包含了webpackBootstrap(webpack模塊加載器)的代碼,按理說(shuō)放在vendor里面也沒(méi)啥問(wèn)題,畢竟后面的模塊都需要依賴于此,但是如果你的chunk使用了hash,一旦app代碼發(fā)生了改變,相應(yīng)的hash值會(huì)發(fā)生變化,webpackBootstrap的代碼也會(huì)發(fā)生變化(如圖),而我們提取vendor的初心就是這部分代碼改變頻率不大,顯然這不符合我們的目標(biāo),那么應(yīng)當(dāng)將webpackBootstrap再提取到一個(gè)文件中,代碼如下:

new webpack.optimize.CommonsChunkPlugin({  name: 'manifest',  chunks: ['vendor']}) 

 

用 import 還是 require

vue 2.2.0 后不能直接使用 require 來(lái)加載 vue,那么到底改是該使用 ES6 Module 還是 CommonJS 呢?,先看一個(gè)對(duì)比圖:

全部使用 ES6 Module,即import、export default,最終打包的app.js為1.20KB。

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

雖然兩者大小相差不大,但是這不禁讓人覺(jué)得用 CommonJS 似乎是一條優(yōu)化措施,那么代碼層面到底是怎么回事呢?

為了一探究竟,注釋了壓縮插件,以about.vue最終構(gòu)建的代碼來(lái)看,使用 CommonJS 的代碼如下:

 (function (module, exports, __webpack_require__) { "use strict"; module.exports = {  data: function data() {   return {    page: 'about'   };  } };}), 

這基本上和 about.vue 中的代碼相差無(wú)幾,而使用 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'   };  } };}), 

對(duì)比兩種規(guī)范下構(gòu)建后的代碼,使用 ES6 Module 主要是多了 Object.defineProperty 那一部分,從而導(dǎo)致了最終打包的文件大一點(diǎn)兒。那是不是為了最終文件體積能小些就全部使用 CommonJS 呢?這個(gè)需要你充分理解 CommonJS 和 ES6 Module 的區(qū)別,引用《ECMAScript 6入門》這本書(shū)的解釋如下:

ES6模塊加載的機(jī)制,與CommonJS模塊完全不同。CommonJS模塊輸出的是一個(gè)值的拷貝,而ES6模塊輸出的是值的引用。

為了更清楚的理解這段話,我們稍微做一下測(cè)試,在 src 下增加一個(gè)test.js,內(nèi)容如下(分別將兩種寫法列出):
 

// CommonJSvar counter = 1;function incCounter() {  counter++;}module.exports = {  counter: counter,  incCounter: incCounter,};// ES6 Moduleexport let counter = 1;export function incCounter() {  counter++;} 

在about.vue中測(cè)試如下:

 // CommonJSvar test = require('../test');export default {  created() {    console.log(test.counter); // 1    test.incCounter();    console.log(test.counter); // 1  }}// ES6 Moduleimport { counter, incCounter } from '../test';export default {  created() {    console.log(counter); // 1    incCounter();    console.log(counter); // 2  }} 

最終的輸出值也印證了前面的解釋,更詳細(xì)的解讀請(qǐng)查閱相關(guān)資料或書(shū)籍。只有深入理解了兩者的區(qū)別,自然就能明白何時(shí)該使用何種規(guī)范。當(dāng)然 ES6 作為未來(lái)的趨勢(shì),我們應(yīng)該去做更多的嘗試。

異步組件(懶加載)

之前用懶加載的方式是:require.ensure,在 webpack2 中引入了 Code Splitting-Async 的新方法 import(),用于動(dòng)態(tài)引入 ES Module。require.ensure 可以指定 chunkFilename,但是 import 沒(méi)有很好的途徑去指定,webpack3 為了解決這個(gè)問(wèn)題,提出了用魔法注釋的方式來(lái)指定模塊名。

結(jié)合 vue-router 可以輕松實(shí)現(xiàn)懶加載,配置路由指向異步組件即可實(shí)現(xiàn)懶加載,比如:

{    path: '/async',    component: () => import(/* webpackChunkName: "async" */'./views/async.vue')} 

如果你發(fā)現(xiàn)使用 import() 運(yùn)行時(shí)報(bào)錯(cuò),有幾種情況:
1.babel presets 配置為 es2015,則不支持動(dòng)態(tài)導(dǎo)入功能,因此需要安裝支持動(dòng)態(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 則不會(huì)解析 import,可以安裝插件 (npm i babel-plugin-syntax-dynamic-import -D)解決。

魔法注釋雖然指定了塊名,但是 webpack 默認(rèn)的塊名配置為 [id].js,即用的模塊的 id 作為塊名,因此需要我們手動(dòng)改下配置。

修改 webpack.base.config.js 的 output:

output: {  filename: 'js/[name].js',  chunkFilename: "js/[name].[chunkhash].js"} 

效果如下圖:

 

如果發(fā)現(xiàn)魔法注釋沒(méi)有生效,要檢查下 .babelrc 的配置項(xiàng) comments 是否設(shè)為 true。或者不配置 comments(默認(rèn)為true)

extract-text-webpack-plugin 默認(rèn)不會(huì)提取異步模塊中的 CSS,需要加上配置:

new ExtractTextPlugin({  allChunks:true,  filename: "css/style.css?[contenthash:8]"}) 

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 邹城市| 阿瓦提县| 东丰县| 花莲市| 富顺县| 尼玛县| 图木舒克市| 咸宁市| 丹凤县| 新兴县| 栖霞市| 阿鲁科尔沁旗| 德兴市| 罗山县| 邵阳市| 广宁县| 万盛区| 上栗县| 德江县| 河津市| 新密市| 印江| 繁昌县| 东乌珠穆沁旗| 思南县| 九寨沟县| 昌图县| 平度市| 东山县| 兰考县| 天长市| 宿州市| 宜君县| 娄底市| 乐安县| 自贡市| 六枝特区| 陇川县| 临潭县| 武川县| 隆回县|