Vue学习-模块化开发

277 阅读5分钟

Vue学习-模块化开发

多个js文件造成的问题

全局变量同名,造成多人开发变量被其他人修改

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>

    <script src="aaa.js"></script>
    <script src="bbb.js"></script>
    <script src="mmm.js"></script>
  </body>
</html>
// 小明开发
// aaa.js
var name = 'xiaoming';
var age = 22;

function sum(num1, num2) {
  return num1 + num2;
}

var flag = true;

if (flag) {
  console.log(sum(10, 20)); // 30
}
// 小红开发
// bbb.js
var name = 'xiaohong';
var flag = false;

console.log(name); // xiaohong
// mmm.js
if (flag) {
  console.log('小明是天才'); // 这里是不会打印出来的
}

匿名函数的解决方案(原始雏型)

函数具有自己的作用域

// 小明开发
// aaa.js
;
var moduleA = (function() {

  var obj = {};

  var name = 'xiaoming';
  var age = 22;

  function sum(num1, num2) {
    return num1 + num2;
  }

  var flag = true;

  if (flag) {
    console.log(sum(10, 20));
  }

  obj.flag = flag;
  obj.sum = sum;

  console.log(obj);

  return obj;
})();
// 小红开发
// bbb.js
;
var moduleB = (function() {
  var obj = {};
  var name = 'xiaohong';
  var flag = false;

  console.log(name);

  obj.flag = flag;
  return obj;
})();
// mmm.js
;(function() {
  if (moduleA.flag) {
    console.log('小明是天才'); // 能够正常打印
  }
})();

常见的模块化规范

  • CommonJs

    模块化的两个核心模块:导出和导入

    CommonJs中的导出

    module.exports = {
    	flag: true,
      test(a, b) {
        return a + b;
      },
      demo(a, b) {
        return a * b;
      }
    }
    

    CommonJs中的导入

    let { test, demo, flag } = require('moduleA');
    // moduleA为导出的文件路径
    
  • AMD

  • CMD

  • ES6中的Modules

    ES6中新增了2个关键字: export import

Index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
	  // 这里要添加type="module"
    <script src="aaa.js" type="module"></script>
    <script src="bbb.js" type="module"></script>
    <script src="mmm.js" type="module"></script>
  </body>
</html>

aaa.js

// 小明开发 aaa.js
let name = 'xiaoming';
let age = 18;
let flag = true;

function sum(num1, num2) {
  return num1 + num2;
}

if (flag) {
  console.log(sum(10, 20));
}

// 1. 导出方式1
export {
flag, sum
}

// 2. 导出方式2
export var num1 = 1000;
export var height = 1.88;

// 3. 导出函数/类
export function mul(num1, num2) {
  return num1 * num2;
}

export class Person {
  run() {
    console.log('run');
  }
}

// 4. export default
// 某些情况下,一个模块包含某个功能,我们并不希望给这个功能命名,而让导入者可以自己来命名,这个时候可以使用export default
// export default在同一个模块中只能存在一个,不允许存在多个
const address = 'beijing';
export default address;

bbb.js

// 小红开发 bbb.js
let name = '小红';
let flag = false;

mmm.js

import { flag, sum } from './aaa.js'

if (flag) {
  console.log('小明是天才');
  console.log(sum(100 , 200));
} 

import { num1, height } from './aaa.js'

console.log('num1 ', num1);
console.log('height ', height);


import { mul, Person } from './aaa.js'
console.log(mul(100, 100));

const p = new Person();
p.run();

import add from './aaa.js'
console.log(add);

// 通配符
import * as aaa from './aaa.js'
console.log(aaa.flag);
console.log(aaa.height);

webpack

认识webpack

模块化 打包 工具

模块化:

webpack其中的一个核心就是帮助我们能够进行模块化开发,并且帮助我们处理模块间的依赖

而且不仅仅是js文件,我们的css,图片,json文件等等在webpack中都可以当作模块

打包:

就是将webpack中的各种资源模块进行打包合并成一个或者多个包

并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转化成css,将es6语法转化成es5语法等等操作

webpack的安装

// 查看node版本
node -v
// 全局安装webpack
npm install webpack@3.6.0 -g

webpack的起步

main.js

const { sum, mul } = require('./mathUtil.js');

console.log(sum(20, 30));
console.log(mul(20, 30));

mathUtil.js

function sum(num1, num2) {
  return num1 + num2;
}

function mul(num1, num2) {
  return num1 * num2;
}

module.exports = {
  sum, mul
}

webpack打包命令

webpack ./src/main.js ./dist/bundle.js

Index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>

    <script src="./dist/bundle.js"></script>
  </body>
</html>

打包出来的bundle.js

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

const { sum, mul } = __webpack_require__(1);

console.log(sum(20, 30));
console.log(mul(20, 30));


/***/ }),
/* 1 */
/***/ (function(module, exports) {

function sum(num1, num2) {
    return num1 + num2;
}

function mul(num1, num2) {
    return num1 * num2;
}

module.exports = {
    sum, mul
}

/***/ })
/******/ ]);

webpack的配置

webpack ./src/main.js ./dist/bundle.js命令缩写成webpack

  1. npm init

  2. 创建webpack.config.js文件

    其中,__dirname指的是本文件所在的绝对路径,entry指的是项目的入口文件,output指的是项目的出口文件,path是出口文件的路径,filename是出口文件的名称,这样配置了以后就可以使用webpack命令代替webpack ./src/main.js ./dist/bundle.js

const path = require('path');

module.exports = {
    entry: './src/main.js',
    output: {
        // 动态获取路径
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    }
}
  1. 使用npm run build命令代替webpack

    npm init之后会自动生成一个package.json文件,在package.json文件的scripts中添加配置"build": "webpack"便可以使用npm run build命令代替webpack,使用npm run build会优先使用本地的webpack

    {
      "name": "meetwebpack",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "webpack"
      },
      "author": "",
      "license": "ISC"
    }
    
  2. 本地安装webpack

    npm install webpack@3.6.0 --save-dev

loader的使用

loader的使用过程

  • 通过npm安装需要的loader
  • 在webpack.config.js中的modules关键字下面进行配置

css文件的处理

npm install css-loader@2.0.2 --save-dev
npm install style-loader --save-dev
module: {
  rules: [
    {
      test: /\.css$/,
      // css-loader只负责css文件的加载,style-loader负责样式的渲染
      use: ['style-loader', 'css-loader']
    }
  ]
}

less文件的处理

npm install less less-loader@5.0.0 --save-dev
{
  test: /\.less$/i,
    loader: [
      // compiles Less to CSS
      'style-loader',
      'css-loader',
      'less-loader',
    ],
}

图片等文件的处理

npm install url-loader@4.1.1 --save-dev
{
  test: /\.(png|jpg|gif)$/i,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 8192,
        },
      },
    ],
}

当图片大小超过limit的时候,会报错,需要使用file-loader

npm install file-loader@3.0.1 --save-dev

运行之后会出现图片请求不到的情况,是因为图片以文件的形式存放在dist目录下,需要在webpack.config.js中添加配置:publicPath: 'dist/'

const path = require('path');

module.exports = {
  entry: './src/main.js',
  output: {
    // 动态获取路径
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        // css-loader只负责css文件的加载,style-loader负责样式的渲染
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/i,
        loader: [
          // compiles Less to CSS
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      }, {
        test: /\.(png|jpg|gif|jepg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8912,
            }
          }
        ]
      }
    ]
  }
}

图片文件名的处理:

增加name配置

{
  test: /\.(png|jpg|gif|jepg)$/,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 8912,
          name: 'img/[name].[hash:8].[ext]'
        }
      }
    ]
}

ES6语法的处理loader

npm install --save-dev babel-loader@7.1.5 babel-core@6.26.3 babel-preset-es2015@6.24.1
{
  test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
          options: {
            presets: ['es2015']
          }
      }
}

webpack中配置vue

npm install vue --save

在webpack.config.js中添加配置,指定使用runtime-compiler版本(默认是runtime-only版本)

resolve: {
  alias: {
    'vue$': 'vue/dist/vue.esm.js'
  }
}

template和el共存时,template中的内容,会把el挂载的dom中的所有元素替换为template中的内容

使用.vue文件

npm install vue-loader@13.0.0 vue-template-compiler --save-dev

注意vue-template-compiler和vue的版本要保持一致

可以不加.vue扩展名,添加extensions配置

resolve: {
  extensions: ['.js', '.css', '.vue'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
}

plugin的使用

版权信息插件

const webpack = require('webpack');
plugins: [
  new webpack.BannerPlugin('最终版权归xx所有')
]

HtmlWebpackPlugin

不是webpack自带的插件,需要手动安装

npm install html-webpack-plugin@3.2.0 --save-dev
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [
  new webpack.BannerPlugin('最终版权归xx所有'),
  new HtmlWebpackPlugin({
    template: 'index.html'
  })
]

压缩js插件

npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
plugins: [
  new webpack.BannerPlugin('最终版权归xx所有'),
  new HtmlWebpackPlugin({
    template: 'index.html'
  }),
  new UglifyjsWebpackPlugin()
]

搭建本地服务器

npm install webpack-dev-server@2.9.3 --save-dev
devServer: {
  contentBase: './dist',
    inline: true // 实时监听
}
// 运行起来
./node_modules/.bin/webpack-dev-server

或者在package.json中配置

// --open自动打开
"dev": "webpack-dev-server --open"
npm run dev

webpack配置文件的分离

npm install webpack-merge@4.1.5 --save-dev

base.config.js

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
  entry: './src/main.js',
  output: {
    // 动态获取路径
    path: path.resolve(__dirname, '../dist'),
    filename: 'bundle.js',
    // publicPath: 'dist/'
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        // css-loader只负责css文件的加载,style-loader负责样式的渲染
        use: ['style-loader', 'css-loader']
      },
      {
        test: /\.less$/i,
        loader: [
          // compiles Less to CSS
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      }, {
        test: /\.(png|jpg|gif|jepg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8912,
              name: 'img/[name].[hash:8].[ext]'
            }
          }
        ]
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['es2015']
          }
        }
      },
      {
        test: /\.vue$/,
        use: ['vue-loader']
      }
    ]
  },
  resolve: {
    extensions: ['.js', '.css', '.vue'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js'
    }
  },
  plugins: [
    new webpack.BannerPlugin('最终版权归xx所有'),
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    // new UglifyjsWebpackPlugin()
  ],
  // devServer: {
  //     contentBase: './dist',
  //     inline: true // 实时监听
  // }
}

prod.config.js

const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig, {
  plugins: [
    new UglifyjsWebpackPlugin()
  ]
})

dev.config.js

const webpackMerge = require('webpack-merge');
const baseConfig = require('./base.config');

module.exports = webpackMerge(baseConfig, {
  devServer: {
    contentBase: './dist',
    inline: true // 实时监听
  }
})

Package.json

这里通过--config来配置build和dev的路径

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