>  기사  >  웹 프론트엔드  >  vue2 vue-router2 webpack3 프로젝트 튜토리얼 빌드

vue2 vue-router2 webpack3 프로젝트 튜토리얼 빌드

小云云
小云云원래의
2018-01-16 09:13:201207검색

이 글은 vue2 vue-router2 webpack3 프로젝트를 처음부터 빌드하는 방법에 대한 자세한 설명을 주로 소개합니다. 편집자가 꽤 좋다고 생각해서 지금 공유하고 참고용으로 제공하겠습니다. 편집자를 따라가서 살펴보겠습니다. 그것이 모두에게 도움이 되기를 바랍니다.

초보자의 관점에서 각 단계의 내용을 자세히 소개하겠습니다. 각 단계에 관련된 원리는 다루지 않고 주로 작동 방법을 소개합니다.

프로젝트 초기화

새 프로젝트 디렉터리 vue2practice를 만들고 디렉터리에서 npm init -y를 실행하여 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의 PeerDependency, npm3은 PeerDependency를 자동으로 설치하지 않지만 vue-template-compiler가 필요한데 작성자가 이를 종속성에 넣지 않는 이유는 무엇입니까? 누군가가 github에서 이 질문을 했습니다. 저자의 답변을 대략적으로 번역하겠습니다(참고용). 그 이유는 중첩된 종속성 관계를 해결할 수 있는 확실한 방법이 없기 때문입니다. 이 문장을 어떻게 이해합니까? 우선, vue-template-compiler와 vue의 버전 번호는 일치합니다(현재 동기식으로 업데이트됨). vue-template-compiler를 vue-loader의 종속성으로 지정한다고 해서 vue-template-compiler와 vue의 버전 번호가 보장되는 것은 아닙니다. vue는 동일하므로 사용자가 버전을 지정할 수 있도록 하면 이를 보장할 수 있습니다. 저자의 답변(영문)을 확인하세요. 두 버전이 일치하지 않는 경우 실행 시 아래 그림과 같은 오류 메시지가 나타납니다.

새 디렉토리 구조는 다음과 같습니다. 먼저 새로 추가된 디렉토리와 파일을 비워두세요. 다음 단계에서는 추가할 내용을 설명합니다.

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를 읽습니다. 파일 이름은 임의로 변경할 수 없으며 항목을 구성해야 합니다.

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는 기본적으로 인라인 모드로 설정되어 있지만 핫 모듈 교체는 여전히 직접 설정해야 합니다.

구성 확인

index.html에 테스트 코드를 추가하고 패키지된 JS 파일을 도입하세요.

<body>

  Hello, Webpack 3.

  <br>

  <script src="/static/build.js"></script>

</body>

main.js에 테스트 코드를 추가하세요.

// main.js

document.write('来自main.js的问候!')

아래 명령어를 실행하여 모듈을 설치하고 서버를 시작하세요.

// 安装依赖

npm install

 

// 运行

npm run dev

시작 후 브라우저는 자동으로 http://localhost:8080을 엽니다. 콘솔에 오류가 보고되지 않으면 페이지에 main.js 및 index.html의 내용이 올바르게 표시됩니다. 브라우저가 새로 고쳐지지 않으며 구성에 문제가 없음을 나타내는 효과가 표시됩니다.

Vue

새 페이지 만들기

views 디렉터리에 새 index.vue를 만듭니다.

<template>

  <p>

    这是{{page}}页面

  </p>

</template>

<script>

export default {

  data: function () {

    return {

      page: 'index'

    }

  }

}

</script>

webpack 1에서는 ES 2015 가져오기/내보내기를 변환하려면 특정 로더가 필요하며, webpack 2 이후부터는 즉시 사용할 수 있습니다. 그러나 ES6의 새 구문을 변환하려면 여전히 로더가 필요합니다. 구성 없이 새 구문을 사용하지 마세요. 이를 사용한 후에는 오류가 보고되지 않습니다(예: let, const 등). 이는 브라우저가 이미 ES6 구문을 지원하기 때문입니다(새 버전의 브라우저에서는 이미 지원함).

라우팅 구성

vue-router가 router.js로 인스턴스화될 때 전달된 새 VueRouter 매개변수(매개변수)를 추출하여 라우팅 구성 파일을 구성합니다.

import index from './views/index.vue'

export default {

  routes: [

    {

      path: '/index',

      component: index

    }

  ]

}

vue-loader@13.0.0에서는 require를 사용하여 .vue 파일을 도입할 수 없습니다. .vue 파일은 결국 ES6 모듈로 컴파일되기 때문입니다.

Homepage

홈페이지에는 출력으로 구성된 JS를 소개하고 Vue 인스턴스의 탑재 대상을 추가합니다.

<body>

<p id="app"></p>

<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')를 사용하면 오류가 보고됩니다. 구체적인 이유는 Vue 업데이트 지침 https://github.com/을 참조하세요. vuejs/vue/releases 스크린샷은 다음과 같습니다.

홈페이지 구성요소 app.vue에 라우팅 링크 및 라우팅 보기 구성요소를 추가합니다.

<template>

  <p>

    <p>

      <router-link to="/index">Home</router-link>

    </p>

    <p>

      <router-view></router-view>

    </p>

  </p>

</template>

로더 구성

vue 파일에 해당하는 로더를 구성하세요.

module: {

  rules: [

    {

      test: /\.vue$/,

      use: ["vue-loader"]

    }

  ]

}

Webpack2는 module.rules 아래에 로더를 구성해야 합니다. '-loader'는 생략할 수 없으며, 로더 이름을 전부 적어야 합니다. 로더를 구성하려면 Rule.use 또는 Rule.loader를 사용할 수 있습니다. (Rule.loader는 Rule.use의 약어: [{ loader } ]) 사용을 권장합니다.

이상으로 새 페이지 추가 및 페이지 접속에 필요한 설정이 완료되었습니다. 이제 /index에 정상적으로 접속이 가능한지 테스트해 보겠습니다. npm run dev를 실행하면 브라우저에 그림과 같은 인터페이스가 표시됩니다.

CSS 지원

css-loader를 설치한 후 vue 파일에서 사용할 수 있습니다.

npm i css-loader -D

CSS 파일 가져오기/요구를 지원하려면 해당 규칙을 구성해야 합니다.

{

  test: /\.css$/,

  use: ["vue-style-loader", "css-loader"]

}
<script>

import "../style/style.css"

</script>

CSS 전처리 언어 지원

스타일러스를 예로 들어 스타일러스와 스타일러스 로더를 설치하세요.

npm install stylus stylus-loader -D

.styl 파일에 해당하는 로더 구성을 추가하세요.

{

  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 느린 설치 솔루션

Taobao 미러 사용:

npm set disturl https://npm.taobao.org/dist

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文件夹下

    }

  }]

}

构建

添加打包命令如下:

"build":"webpack --progress --colors"

执行npm run build开始构建,完成后,可以看到工程目录下多了dist目录以及 dist/build.js。 

使用 Webpack 插件

压缩JS

在之前的文章提到过,打开未压缩版的build.js,你会发现ES6的语法没有被转化为ES5,因此需要安装babel 套件来完成语法的转化,否则压缩的时候就会报错。之前广泛使用的转码规则为 babel-preset-es2015,但 Babel 的官网上在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 设置为 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()

官网称warnings默认为false,你可能会遇到即使没有配置warnings: true,控制台仍显示警告,看下面这段源码就知道了。查看源码

只有当options.compress !== false时 warnings 才会被设置默认值 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,需要设置 vue-loader 参数才可以。

{

  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 预处理语言 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 使用中发现有些问题。如果想禁用这个插件的话,配置如下:

require('cssnano')({

  zindex: {

    disable:true

  }

})

附:postcss插件分类搜索网站: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()

指定生产环境,以便在压缩时可以让 UglifyJS 自动删除代码块内的警告语句。

new webpack.DefinePlugin({

  'process.env.NODE_ENV': JSON.stringify('production')

})

因为这个插件直接做的文本替换,给定的值必须包含字符串本身内的实际引号。通常,有两种方式来达到这个效果,使用 '"production"', 或者使用 JSON.stringify('production')。

你完全可以在自己的代码中使用process.env.NODE_ENV来区分开发和生产,从而针对不同的环境做一些事情。不用担心这部分代码会被保留,最终会被 UglifyJS 删除。例如:

if (process.env.NODE_ENV != "production") {

  // 开发环境

}

// webpack.DefinePlugin插件替换后,上述代码会变成

if ("production" != "production") {

  // 开发环境

}

// 输出

if (false) {

  // 开发环境

}

// UglifyJS 会删除这段无效代码

使用上述插件后再次构建,会发现生成的JS相比原来的体积小了不少。

friendly-errors-webpack-plugin 是一个更友好显示 webpack 错误信息的插件。插件 github 地址:https://github.com/geowarin/friendly-errors-webpack-plugin

一般在开发环境下使用。

var FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

 

var webpackConfig = {

 // ...

 plugins: [

  new FriendlyErrorsWebpackPlugin(),

 ],

 // ...

}

效果如下图:

显示构建进度插件:webpack.ProgressPlugin

{

 // ...

 plugins: [

  new webpack.ProgressPlugin(),

 ],

 // ...

}

效果如下图:

美化 webpack 编译控制台打印的信息的插件webpack-dashboard

分离Webpack配置

将开发和生产配置文件分离,方便增加各个环境下的个性配置。Webpack2文档中也详细阐述了如何为多环境配置webpack。基本思路如下:

  1. 编写一个基本配置文件(webpack.base.config.js)

  2. 使用webpack-merge合并这个基础配置和针对环境的特定的配置(webpack.dev.config.js,webpack.prod.config.js)

webpack.base.config.js 内容如下:

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预处理语言的loader,开发环境可以不用配置,但是生产环境需要提取CSS、增加postcss-loader等,因此需要提取出来针对不同环境返回相应的options。后面会列出utils.vueLoaderOptions的内容。

为什么没有配置CSS的loader?理由和上面的vue-loader一样。

为什么没有配置path和publicPath?一方面是个性化参数,另外开发和生产可能不相同,因此在webpack.dev.config和webpack.prod.config中分别配置更为合适。

webpack.dev.config.js 内容如下:

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了,会自动根据打包的JS添加引用,这样更加方便,关于HtmlWebpackPlugin的配置,需要说明两点:

1.template的路径是相对于webpack编译时的上下文目录,说白了就是项目根目录,因此上面可以直接配置index.html,其指向的就是根目录下的index.html;

2.filename则是相对于webpack配置项output.path(打包资源存储路径)。

html-webpack-plugin关于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内容如下:

module.exports = {

  dev: {

    outputPath: path.resolve(__dirname, '../static'),

    outputPublicPath: '/',

    port: 8000

  },

  prod: {

    outputPath: path.resolve(__dirname, '../static'),

    outputPublicPath: '/static/'

  }

}

utils.js内容如下:

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

var isProd = process.env.NODE_ENV === "production";

// 根据项目需求添加CSS预处理语言并安装相应的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) {

    // 生产环境需要提取CSS

    loaders = ExtractTextPlugin.extract({

      use: loaders

    });

  } else {

    // 开发环境需要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中间件做开发服务器,其实用webpack-dev-server就能满足需求,当然用express能够做更多的事情,毕竟webpack-dev-server是一个轻量级的express。dev.js内容如下:

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}`);

})

生产配置文件(webpack.prod.config.js)内容如下:

// 设定为生产环境

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

    })

  ]

})

生产构建(prod.js)内容如下:

var webpack = require("webpack");

var webpackProdConfig = require('./webpack.prod.config');

webpack(webpackProdConfig, function(err, stats) {

  process.stdout.write(stats.toString());

});

对应在package.json中添加开发和生产构建的命令如下:

"scripts": {

  "dev": "node build/dev.js",

  "build": "node build/prod.js"

}

代码分割

参照vue-cli及webpack文档的提取公共代码的方式,利用插件webpack.optimize.CommonsChunkPlugin将来自node_modules下的模块提取到vendor.js(一般来讲都是外部库,短时间不会发生变化)。于是有如下代码:

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,会发现不仅包含vue的代码,还包含了webpackBootstrap(webpack模块加载器)的代码,按理说放在vendor里面也没啥问题,毕竟后面的模块都需要依赖于此,但是如果你的chunk使用了hash,一旦app代码发生了改变,相应的hash值会发生变化,webpackBootstrap的代码也会发生变化(如图),而我们提取vendor的初心就是这部分代码改变频率不大,显然这不符合我们的目标,那么应当将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 似乎是一条优化措施,那么代码层面到底是怎么回事呢?

为了一探究竟,注释了压缩插件,以about.vue最终构建的代码来看,使用 CommonJS 的代码如下:

 (function (module, exports, __webpack_require__) {

 "use strict";

 module.exports = {

  data: function data() {

   return {

    page: 'about'

   };

  }

 };

}),

这基本上和 about.vue 中的代码相差无几,而使用 ES6 Module 构建的代码如下:

(function (module, exports, __webpack_require__) {

 "use strict";

 Object.defineProperty(exports, "__esModule", {

  value: true

 });

 exports.default = {

  data: function data() {

   return {

    page: 'about'

   };

  }

 };

}),

对比两种规范下构建后的代码,使用 ES6 Module 主要是多了 Object.defineProperty 那一部分,从而导致了最终打包的文件大一点儿。那是不是为了最终文件体积能小些就全部使用 CommonJS 呢?这个需要你充分理解 CommonJS 和 ES6 Module 的区别,引用《ECMAScript 6入门》这本书的解释如下:

ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。

为了更清楚的理解这段话,我们稍微做一下测试,在 src 下增加一个test.js,内容如下(分别将两种写法列出):
 

// 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

  }

}

最终的输出值也印证了前面的解释,更详细的解读请查阅相关资料或书籍。只有深入理解了两者的区别,自然就能明白何时该使用何种规范。当然 ES6 作为未来的趋势,我们应该去做更多的尝试。

异步组件(懒加载)

之前用懒加载的方式是:require.ensure,在 webpack2 中引入了 Code Splitting-Async 的新方法 import(),用于动态引入 ES Module。require.ensure 可以指定 chunkFilename,但是 import 没有很好的途径去指定,webpack3 为了解决这个问题,提出了用魔法注释的方式来指定模块名。

结合 vue-router 可以轻松实现懒加载,配置路由指向异步组件即可实现懒加载,比如:

{

    path: '/async',

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

}

如果你发现使用 import() 运行时报错,有几种情况:
1.babel presets 配置为 es2015,则不支持动态导入功能,因此需要安装支持动态导入的 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"

}

效果如下图:

 

如果发现魔法注释没有生效,要检查下 .babelrc 的配置项 comments 是否设为 true。或者不配置 comments(默认为true)

extract-text-webpack-plugin 默认不会提取异步模块中的 CSS,需要加上配置:

new ExtractTextPlugin({

  allChunks:true,

  filename: "css/style.css?[contenthash:8]"

})

相关推荐:

webpack和vue2构建vue项目骨架讲解

关于vue2.0设置proxyTable使用axios进行跨域请求

简单了解vue2 单页面如何设置网页title

위 내용은 vue2 vue-router2 webpack3 프로젝트 튜토리얼 빌드의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.