一. 模块化开发
eg: 有不同的模块,它们有单独的作用域,就不会出现命名冲突的问题。
var moduleA = (function(){
//导出的对象
var obj = {}
var name = '小敏'
var age = 18
function sum(num1,num2) {
return num1 + num2;
}
var flag = true
if(flag) {
console.log(sum(10,20));
}
obj.flag = flag; //开发中不同的js文件可能定义相同的变量,就会出现命名冲突问题
obj.sum = sum;
return obj; //使用一个对象将数据封装成一个单独的模块来调用,就不会出现冲突
})()
01 CommonJS (node常用)
- 模块化有两个核心:导出和导入
- 代码不需要再函数里面,因为模块化中一个js文件就可以看成一个模块,这个模块有自己的作用域
- 语法:
//导出
moduleA.expotrs = {
flag:flag,
sum:sum
}
//导入
var {flag,xum} = require('./one.js') //从one.js文件中导入
//等同于:
var one = require('./one.js')
var flag = one.flag;
var sum = one.sum;
02 ES模块化的导入和导出
-
export (导出) / import (导入)
-
导入文件时出现一个跨域请求失败的错误:解决方法
-
模块在自己独立的空间里随意命名,不会和其他人冲突,但是别人也不能访问,当别人想访问的时候,必须先导出,别人导入才能访问。
index.html
<body>
<script src="aaa.js" type="module"></script> <!-- 类型需要设置为module,才可以使用导入导出语法 -->
<script src="bbb.js" type="module"></script>
<script src="mmm.js" type="module"></script>
</body>
导出
var name = '小敏'
var age = 18
var flag = true
function sum(num1,num2) {
return num1 + num2;
}
if(flag) {
console.log(sum(20,30));
}
//1 导出方式一:
export {
flag,
sum
}
//2 导出方式二:在定义变量的时候就导出
export var num = 1000;
export var height = 1.88
//3 导出函数/类
export function mul(num1,num2) {
return num1 * num2;
}
export class Person {
run(){
console.log("在奔跑");
}
}
//4 export default -- * export default在同一个模块中,不允许同时存在多个
//通常情况下,一个模块中包含某个功能,我们不希望给这个功能命名,而且让导入者可以自己来命名
// const address = "北京市"
// export default address //export default
export default function (argument) {
console.log(argument);
}
导入
//1 导入的是{}定义的变量
import {flag, sum} from "./aaa.js";
if(flag) {
console.log("小敏啦啦啦啦");
console.log(sum(20,30));
}
//2 直接导入export定义的变量
import {num,height} from "./aaa.js"
console.log(num);
console.log(height);
//3 导入 export导出的function
import { mul,Person } from "./aaa.js";
console.log(mul(14,25));
const p = new Person();
p.run();
//4 导入的默认导出函数
import addr from "./aaa.js" //导出的是default中的,名字可以随意
// console.log(addr);
addr("你好啊")
//5 统一全部导入
// import {flag,num,num1,height,Person,mul,sum} from "./aaa.js" 不建议这样写,可能与自己的变量冲突
import * as aaa from "./aaa.js" //aaa是名字
console.log(aaa.flag);
console.log(aaa.height);
二. Webpack
- webpack是一个现代JavaScript应用的静态模块打包
- webpack为了可以正常运行,必须依赖node环境 —> node环境为了可以正常地执行很多代码,必须其中包含各种依赖的包 —> npm工具(node package manager 包管理工具)
- webpack的安装:
* 首先要安装node.js,node.js自带软件包管理工具
* npm install webpack@3.6.0 -g安装指定版本的webpack
在安装过程中发现用npm下载很慢,可以换一个下载源:解决
(这是我的配置,后续可能还要改)
2. webpack的基本使用过程
//mathUtils.js
function add(num1,num2) {
return num1 + num2;
}
function mul (num1,num2) {
return num1 * num2;
}
//commonJS
module.exports = {
add,
mul
}
info.js
// es6的导出方式
export const name = 'why'
export const age = 18
export const height = 1.88
入口函数
//1 使用common.js的规范
const {add,mul} = require ("./mathUtils.js")
console.log(add(20,30));
console.log(mul(20,30));
//2 使用es6的模块化的规范
import {name,age,height} from './info'
console.log(name);
console.log(age);
console.log(height);
- 使用webpack打包
<!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>
<!-- 直接引用打包好的文件,如果直接引入js文件,浏览器不识别其中的模块化代码 -->
<script src="./dict/bundle.js"></script>
</body>
</html>
3. webpack.config.js配置和package.json配置
以上配置我们需要在执行webpack命令时指定要打包的文件和目标文件,但是我们也可以通过配置来简化命令。
- 创建webpack.config.js
配置入口和出口,output要写成对象形式,这里我们需要使用到node的语法,用来寻找路径。
const path = require('path') //node语法 -- 导入依赖包
module.exports = {
entry:'./src/main.js', //入口
output:{
path:path.resolve(__dirname,'dist'), //动态获取路径(绝对) -- (__dirname可以获取文件所在路径,进行拼接)
filename:'bundle.js'
} //出口
}
- 终端:npm init
- 配置完webpack.config.js之后,我们可以在终端直接webpack进行打包,但是我们一般不使用这种方式.
我们会把这个命令再做一层映射,使用npm的命令来打包。
- 我们还可以本地按照webpack,用来和项目使用的webpack版本保持一致,因为全局安装的webpack可能和你需要的版本不一致。
注意:只要在终端里使用webpack命令,使用的都是全局的webpack,但是我们在package.json中定义了build,它在执行时会先从本地的node_modules/bin中寻找,本地没有再去全局的环境变量中找。
3. webpack
01. webpack中使用css文件的配置
- loader介绍
- loader 使用:webpack解析打包css文件需要对应的loader
先下载loader,然后在webpackage.config.js中配置loader
- 报错:加载css文件必须有对应的loader
- 按照上面官方给的用法,安装css-loader来加载css文件,但是它并比负责将css具体样式嵌入到文档中,我们还需要style-loader来处理。(注意:style-loader应该放在class-loader前面,因为webpack在读取loader的过程中,是按照从右向左的顺序读取的)
02. webpack中使用less文件的配置
1.编写less文件并引入依赖:
//special.less
@fontSize:50px;
@fontColor:orange;
body {
font-size: @fontSize;
color: @fontColor;
}
//main.js
//4 依赖less文件
require("./css/special.less")
- 直接打包会报错,在使用前必须先安装对应的loader
- 安装: 官方配置
less-loader负责将less文件加载,less是对less文件进行转换的
- 配置:
- 进行打包:npm run build 不再报错,less的样式被应用到html中。
03. webpack 图片文件的处理
- 安装对应的loader (url)
- 配置:
{
test: /\.(png|jpg|gif)$/, //图片文件
use: [
{
loader: 'url-loader',
options: {
//当加载的图片,小于limit时,会将图片编译成base64字符串形式
//当加载的图片,大于limit时,会使用file-loader进行加载
limit: 8196, //8kb
//在dist下创建img文件夹,命名为:文件名.哈希值截取8位,[]里的都是变量,ext为扩展名
name:'img/[name].[hash:8].[ext]'
},
}
]
},
- 注意:大图片若大于limit,则会使用file-loader对图片进行加载,file-loader不需要特别配置,直接安装即可:
安装之后,再次打包,webpack会将图片复制到dist文件夹中,并重新命名(哈希值:不重复),但是我们会发现图片没有显示,这是因为图片的路径不正确:
* 默认情况下,webpack会将生成的路径直接返回给使用者
* 但是,我们整个程序是打包在dist文件下的,所以这里我们需要在路径下添加一个dist/
- 配置之后,只要涉及url,都会自动在路径前拼接 dist/
- webpack自动生成的文件名是一个哈希值,目的是为了放置名字重复,我们可以自己设置将图片放在一个文件夹中,并且对命名进行规范:
在options中添加:name:‘img/[name].[hash:8].[ext]’
04. webpack ES6转ES5的babel
- 安装:
- 配置:
{
test: /\.js$/,
//在对es6转换的时候,排除这些内容,只需要转换src中的js即可
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
}
- 效果:重新打包之后,会发现bundle.js文件中的es6相关代码变量都转成es5的了。
05. webpack 配置vue
- 使用npm命令安装vue
- 导入:
main.js
//5 使用vue进行开发
import Vue from 'vue'
const app = new Vue({
el:'#app',
data:{
message:'Hello Webpack'
}
})
注意:现在打包会报错,因为(我们使用的是runtime-only)版本不太正确。
01 runtime-only ---- 代码中,不可以有任何template
02 runtime-compiler ---- 代码中,可以有template,因为有compiler可以用于编译template。
- 配置:
module.exports = {
entry:'./src/main.js', //入口
output:{...},//出口
module: {...},
resolve:{
alias:{ //别名
'vue$':'vue/dist/vue.esm.js' //当使用vue这个变量时,会到这个文件里找,它支持有模板
}
}
}
- 此时,再次打包,在index.html中使用mustache语法可以获取message的值显示。
三. Vue
1. el和template的区别
当同时有el和template,template会将el挂载id的内容替换掉。
2. Vue的终极使用方案(封装)
- 原先我们在main.js中是这样写的:实现了index.html中格式一致,不需改动,因为内容都放在vue中,template会在执行后替代挂载的div的内容。
这样将内容都放在vue里是比较杂乱的,之后可能会有更多的内容扩充。
//5 使用vue进行开发
import Vue from 'vue'
new Vue({
el:'#app',
template:`
<div>
<h2 class="title">{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
`,
data:{
name:'pao',
message:'Hello Webpack'
},
methods:{
btnClick(){
console.log("点击");
}
}
})
- 我们可以将模板、方法、数据抽取出来为一个组件,之后在vue中引用这个组件即可:
//app.js
export default { //抽取后导出
template:`
<div>
<h2 class="title">{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
`,
data() {
return {
name:'pao',
message:'Hello Webpack'
}
},
methods:{
btnClick(){
console.log("点击");
}
}
}
//main.js
import App from './vue/app.js'
new Vue({
el:'#app',
template:'<App/>',
components:{
App
}
})
- 上面的app.js文件中,我们可以发现,模板、数据、方法是没有分离开来的,我们可以使用vue文件分离,使之更加简洁。之后,同样在main.js中进行引用。
//App.vue
<template>
<div>
<h2 class="title">{{message}}</h2>
<button @click="btnClick">按钮</button>
<h2>{{name}}</h2>
</div>
</template>
<script>
export default {
name:"App",
data() {
return {
name:'pao',
message:'Hello Webpack'
}
},
methods:{
btnClick(){
console.log("点击");
}
}
}
</script>
<style scoped>
.title {
color: blueviolet;
}
</style>
//main.js
import App from './vue/App.vue'
new Vue({
el:'#app',
template:'<App/>',
components:{
App
}
})
- 注意:在使用vue文件时,我们同样需要先安装对应的loader才能解析:
- 配置:
//webpack.config.js
{
test: /\.vue$/,
use: ['vue-loader']
}
- 注意:这里npm run build会报错:原因是我们使用的vue-loader版本是15.4.2,高版本的loader还需要额外配置一个文件(之后学),我们可以在package.json中将vue-loader版本改低,并重新安装一下npm install
终端:npm install 重新安装 — > npm run build重新打包,这时候.vue文件就可以正常加载、正常编译了。
- 以后,我们就可以使用这种方式来编写vue文件,通过导入导出来组建模块,最终会形成一颗组件树,每个组件都是一个独立的模块。
//Cpn.vue
<template>
<div>
<h2>我是cpn组件的标题</h2>
<p>我是cpn组件的内容,哈哈哈</p>
<h2>{{name}}</h2>
</div>
</template>
<script>
export default {
name:"Cpn",
data() {
return {
name:'CPN组件的name',
}
},
}
</script>
<style scoped>
</style>
//App.vue
<template>
<div>
...
<Cpn></Cpn> //使用组件
</div>
</template>
<script>
import Cpn from './Cpn.vue'
export default {
name:"App",
components:{
Cpn //注册导入的组件
},
...
}
</script>
- 注意:在引入文件的时候,如果没有加文件的后缀名,可能会报错,我们可以在webpack.config.js中配置: 这样我们在引用文件的时候就可以不加后缀名了。
resolve:{
extensions:['.js','.css','.vue'],
...
}
四. Webpack 核心
1. 横幅Plugin的使用
1.BannerPlugin,属于webpack自带的插件,可以为打包的文件添加版权声明。
- 配置:
//webpack.config.js
const webpack = require('webpack')
...
module.exports = {
...
plugins:[
new webpack.BannerPlugin('最终解释归泡泡所有')
]
}
我们可以在bundle.js开头看见自己定义的声明。
2. 打包html的Plugin
- 安装html-webpack-plugin
-
配置:
-
dist文件夹中自动生成index.html文件,并且他会自动帮我们引用bundle.js文件
因为之前为了在外面获取dist文件夹内容,我们设置了 publicPath:‘dist/’,但是现在我们的index.html也在dist文件夹中,所以可以删除之前的路径配置了。
3. UglifyjsWebpackPlugin的使用
-
项目发布之前,我们需要对js等文件进行压缩处理,这里要使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致。
-
配置:
当然,每次使用插件前要先require引入插件。
- 效果:bundle.js中的js代码都被压缩了,注释和声明也被删掉了。(开发阶段不建议使用,不方便调试)
4.webpack-dev-server搭建本地服务器
- 使用之前需要安装webpack-dev-server
- 配置:
- 启动服务:
因为在终端敲的命令都默认全局,而我们刚才装的服务是运行时的,所以需要找当前项目服务的路径来执行:
-
方式一:
-
方式二:直接使用配置的方式,这里的命令是从项目开始找的:
//package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"dev":"webpack-dev-server" //"dev":"webpack-dev-server --open"
},
配置后我们可以直接使用npm run dev来启动服务:(配置了参数 --open之后会打动打开浏览器,没配置则要手动点击链接)
3. 现在我们更改页面的内容,浏览器会自动刷新,这样可以方便我们测试,测试完毕之后再执行npm run build自动打包。
5.webpack 配置文件的分离
- 配置文件中,有一些配置是开发时需要,有些配置是生产时需要,我们可以把这些配置单独抽离封装:
(将原本webpack.config.js配置文件分离成三个js配置文件)
//base.config.js 放置公共的配置
const path = require('path') //node语法 -- 导入依赖包
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
entry:'./src/main.js', //入口
output:{...
},//出口
module: {...
},
resolve:{...
},
plugins:[
new webpack.BannerPlugin('最终解释归泡泡所有'),
new HtmlWebpackPlugin({
template:'index.html' //找到配置文件所在目录下的index.html作为模板来生成dist目录中的index.html
}),
// new UglifyjsWebpackPlugin() //发布阶段使用,开发阶段不推荐
],
//开发时需要
// devServer:{
// contentBase:'./dist', //服务于根目录下的dist文件夹,默认是根文件夹
// inline:true, //配置是否实时监听
// }
}
//dev.config.js
//开发时需要的配置,其他的在base(公共)中
module.exports = {
devServer:{
contentBase:'./dist', //服务于根目录下的dist文件夹,默认是根文件夹
inline:true, //配置是否实时监听
}
}
//prod.config.js
//生产时需要的配置
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins:[
new UglifyjsWebpackPlugin()
]
}
- 我们要把配置文件合并起来,需要先装一个插件:
- 配置:
//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
//开发时需要的配置,其他的在base(公共)中
const WebpackMerge = require('webpack-merge')
const baseConfig =require('./base.config')
module.exports = WebpackMerge(baseConfig,{
devServer:{
contentBase:'./dist', //服务于根目录下的dist文件夹,默认是根文件夹
inline:true, //配置是否实时监听
}
})
- 合并之后,我们就不需要webpack.config.js了,但是需要重新配置一下打包命令:
- 注意:此时打包后,会在build中创建dist文件夹存放打包后的文件,是因为output出口设置了在当前文件夹路径下拼接.dist,我们应该设置它回到上一级拼接:
- 测试:
- npm run build:会在build上一级的目录下生成dist文件夹(之前删除了),里面包含我们打包后的文件。
- npm run dev:会自动打开浏览器,展示页面,并且一旦修改页面,浏览器会实时刷新。
6.Vue CLI
- Vue CLI的使用前提 – node
- 安装nodejs可以直接在官方网站下载:nodeJs
- node环境要求8.9或以上或者更高版本(我使用的是12版本)
- 安装Node默认会安装NPM(Node Package Manager),他是一个NodeJs包管理工具,已经成为了非官方的发布Node模块(包)的标准。
- 安装脚手架 教程
- 查看vue版本,看是否安装成功:
- 注意:之前安装node的时候,我还修改了node的全局安装路径,如果安装得不对可能会出现vue不是系统命令的错误,建议还是不要修改它的配置了。(更改npm全局安装路径)
- 我们现在安装的是脚手架3,但是还希望使用脚手架2,那么我们需要拉取脚手架2的模板。(官方)
- Vue CLI2初始化项目
-
解释:
-
Vue CLI3 初始化项目:vue create my-project(后面学)
7.Vue-CLI2的目录结构解析
五. 总结回顾
- 本教程参照B站codewhy老师的课程,在插件等安装的版本都是采用视频教学中的版本,如果不指定版本,一般会安装最新的,可能会不适配。
老师的webpack配置相关版本:
webpack
npm install webpack@3.6.0
css-loader
npm install css-loader@2.0.2 --save-dev
style-loader
npm install style-loader@0.23.1 --save-dev
less-loader
npm install --save-dev less-loader@4.1.0 less@3.9.0
url-loader
npm install --save-dev url-loader@1.1.2
file-loader
npm install --save-dev file-loader@3.0.1
es6转换成es5
npm install --save-dev babel-loader@7.1.5 babel-core@6.26.3 babel-preset-es2015@6.24.1
Vue
npm install vue@2.5.21 --save
npm install --save-dev vue-loader@15.4.2 vue-template-compiler@2.5.21
部分省略...
- 大纲概括:
一.组件化开发
1.1 父子组件的访问
* children / $refs
* parent / root
1.2 插槽slot的使用
* 基本使用
* 具名插槽
* 编译的作用域
* 作用域插槽
二.前端模块化
2.1 为什么要使用模块化
* 简单写js代码带来的问题
* 闭包引起代码不可复用
* 自己实现了简单的模块化
* AMD / CMD / CommonJS
2.2 ES6中模块化的使用
* export
* import
三.webpack
3.1 什么是webpack
* webpack和gulp对比
* webpack依赖环境
* 安装webpack
3.2 webpack的起步
* webpack命令
* webpack配置:webpack.config.js / package.json(scripts)
3.3 webpack的loader
* css-loader / style-loader
* less-loader / less
* url-loader / file-loader
* babel-loader
3.4 webpack配置vue
* vue-loader
3.5 webpack的plugin
3.6 搭建本地服务器
* webpack-dev-server
3.7 配置文件的分离
四.Vue CLI
4.1 什么是CLI
* 脚手架是什么东西
* CLI依赖webpack,node,npm
* 安装CLI3 -> 拉取CLI2模板
4.2 CLI2初始化项目的过程
4.3 CLI2生成的目录结构解析