模块化开发
-
模块化的基础封装
//可以使用匿名函数,闭包解决重名问题,即防止其他模块中也存在相同的变量名称 var ModuleA = (function(){ //定义一个对象作为模块的出口,这样可以将需要的属性和方法暴露到外面 var obj = {} //在对象内部添加变量 obj.flag = true obj.sum = function(info){ console.log(info) } //将对象返回,这样可以在外面使用一个MoudleA接受 return obj })()
-
模块化规范
—使用闭包会引起代码不可复用,因此需要模块化;
—常见的模块化规范:CommonJS、AMD、CMD,也有ES6中的Modules;
CommonJS
—模块的核心中有两个核心:模块导出和导入;
—CommonJS的导出:
module.exports = { //需要导出的内容 name:"Tom" }
—CommonJS的导入:
let {test ,name} = require('./module.js'); //相当于下列写法: let _m = require('./module') let test = _m.test let name = _m.name
-
ES6中的模块导入和导出
—ES6中新增两个关键字,一个为
export
导出关键字和import
导入关键字;export
的基本使用—导出方式一:
export{flag,sum}
;—导出方式二:
export var num = 10
;—导出函数:
export function sum(num1,num2){return num1+num2}
—导出类:
export class Person(){}
—
export default
:某些情况下,一个模块中包含某个功能,我们并不希望给这个功能命名,而是让导入者可以自己来命名,这个时候可以使用export default
;开发中只能在一个模块中有一个export default
;在同一个模块中,不允许存在多个;例如:
导出:
export default function(){console.log("Tom")}
导入:
import sayName from './module.js'
import
的基本使用—首先需要引入js文件,并且保证
script
标签内部的type
类型为module
;<script src = module.js type = "module"><script>
—导入方式:
import {} from './module.js'
—统一全部导入方式:
import * as module from "./module.js"
-
Webpack
认识Webpack
—本质上来讲,Webpack是一个现代的JavaScript应用的静态模块打包工具;简单理解就是webpack可以作为底层支撑,支持模块化的所有规范,统一处理并且打包称为浏览器可以识别的代码,更好的完成模块化;
—webpack正常执行必须依赖于node环境,node环境中为了正常执行代码,必须包含各种依赖的包,通常通过npm工具帮助管理node中的各种包;
—在ES6之前,我们要进行模块化开发,必须借助于其他的工具,作为底层支撑才可以进行模块化开发,并且通过模块化开发完成了项目后,还需要处理模块之间的各种依赖,并且将其进行整合打包;
—Webpack的核心就是模块化开发,并且可以处理模块间的依赖关系;并且不仅仅是JavaScript文件,像CSS、图片、json文件等都会在Webpack中可以被当作模块使用;
—打包就是将Webpack中的各种资源块进行打包合并成一个或者多个包,并且在打包的过程中,还可以进行资源处理,比如压缩图片、将scss转成css,将ES6语法转成ES5语法,将TypeScript转换为JavaScript等操作;
—和grunt/gulp的对比:
- grunt和gulp的核心是Task,可以配置一些列的task,并且定义task要处理的事物(图片压缩、ts转化、scss转成css等);之后让grunt/gulp来一次执行这些task,而且让整个流程自动化;
- grunt/gulp也被称为前端自动化任务管理工具;
- 如果工程模块依赖简单,甚至没有用到模块化的概念,只需要简单的合并、压缩,即使用grunt/gulp即可;但是整个项目中使用模块化管理,并且依赖性很强,就可以使用更加强大的webpack;
- grunt/gulp更加强调的是前端流程的自动化,模块化不是核心;而webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能是他的附带功能;
- webpack正常运行必须依赖node环境,而node环境正常运行必须包含各种依赖的包,即**需要npm工具(node packages manager)**可以帮助管理各种node依赖包;
—全局安装webpack(可以在任何终端下进行webpack操作),可以安装3.6.0,因为vue cli2依赖该版本:可以使用npm进行安装
npm install webpack@3.6.0 -g
查看安装的webpack版本命令:
webpack --version
—局部(本地)安装,当在package.json中定义了scripts时,其中包含了webpack命令,那么就是使用的局部webpack;一般使用本地安装,开发时依赖,项目打包后就不需要继续使用了;
在本地安装输入命令:
npm install webpack@3.6.0 --save-dev
—只要在终端直接敲入命令
webpack
,使用的都是全局webpack;但是我们在package.json中定义的执行脚本,会优先在本地webpack(node_modules/.bin)中寻找;webpack基本使用过程
—webpack中会包含两个文件夹:src和dist;
—在src中进行项目代码开发,dist是webpack打包以后的发布在服务器的内容;
—webpack打包过程的命令:
(1)切换到项目根文件:
cd 根文件夹名称
(2)使用webpack工具进行打包:
webpack ./src/main.js(需要打包的入口文件) ./dist/bundle.js(打包后的输出文件)
—webpack配置文件:
需求:直接在终端写入webpack就可以知道将目标入口文件打包到dist中的输出文件;
(1)创建一个webpack.config.js配置文件;
(2)在配置文件中分别设置入口文件和出口文件:
//通过node包获取路径,依赖node包 //然后再全局进行搜索path const path = require('path') module.exports = { entry:'./src/main.js', output:{ //路径需要使用绝对路径 //所以需要动态获得文件路径,使用node语法 path:path.resolve(__dirname,'dist'), filename:'bundle.js' } }
(3)我们需要动态获取输出文件的路径,所以需要用到node语法,在获取路径前需要进行初始化:
npm init
然后分别设置包名称、描述(可不写)、入口文件(暂时用不到),一路回车,最后生成了package.json文件(任何使用node环境的,都会生成一个package.json文件);
(4)如果代码中需要使用node依赖,需要执行:
npm install
;(5)在出口文件中通过
path.resolve()
对全局上下文所在路径进行拼接,其中__dirname
是全局变量(可以理解为当前绝对路径);(6)可以使用
npm run package.json下scripts中的执行脚本名称
-
Webpack loader
webpack中核心loader
—在开发过程中,不仅仅有js代码处理,我们需要加载css、图片,也包括一些高级的将ES6转换为ES5代码,将TypeScript转换成为ES5代码,将scss、less转换为css,.jsx、vue文件转换为js文件等等,webpack本身对这些转化是不支持的,但是给webpack扩展对应的loader就可以;
—loader使用过程
(1)通过npm安装需要使用的loader,不同的转化需要不同的loader;
(2)在webpack.config.js中的module关键字下进行配置;
大部分loader可以在webpack官网中找到,并学习对应的用法;
CSS文件处理:
(1)在src中创建一个css目录文件夹,然后在该文件夹下创建css文件;
(2)依赖css文件,必须要在入口文件中进行引用,通过
require('./css/normal.css')
;(3)在官网中找到相应的loader进行安装
npm install --save-dev css-loader
,并在webpack.config.js文件中按照官网进行配置;(4)进行项目打包,但是此时样式并没有生效;
(5)因为css-loader只负责将css文件进行加载,而需要一个style-loader将模块的导出作为样式添加到DOM中生效;但是一定要注意!!使用多个loader时,是从右向左进行加载;
less文件处理:
(1)我们在项目中希望使用less、scss和stylus来写样式,例如less文件,创建less文件,放在css文件夹下;
(2)依赖less文件,必须在入口文件中进行引用,通过
require('./css/special.less')
(3)安装loder并进行webpack.config.js配置;
(4)项目打包
npm run build(自定义脚本执行名称)
图片文件处理
(1)在项目中需要使用图片文件,可以创建一个图片文件img,并将需要的图片文件保存在该文件夹下;
(2)依赖图片文件,必须在入口文件中引用该图片文件的css文件
(3)图片属于文件,因此在loader中寻找文件,安装url-loader和webpack.config.js配置;
(4)项目打包
当图片大小小于
options
中的limit
时,会将图片编译成base64字符串形式;如果大于limit
时,会使用file-loader;**注意!!**当使用file-loader时,会在dist文件夹下多了一个图片文件(32位哈希值命名的图片,防止名字重复),因此需要对打包后的图片路径进行修改,即需要修改webpack.config.js配置,在该配置文件下
output
中添加publicPath:dist/
,这样只要涉及url
路径问题都会自动添加dist/
;—可以在
options
中添加如下选项:(1)img:文件要打包到的文件夹;
(2)name:获取图片原来的名字,放在该位置;
(3)hash:为了防止图片名冲突,依然使用hash哈希值,但是我们只保留8位
(4)ext:使用图片原来的扩展名
语法如下:
name:'img/[name].[hash:8].[ext]'
ES6语法转换
(1)直接使用
babel
对应的loader就可以;(2)配置webpack.config.js文件;
(3)重新打包,查看bundle.js文件,发现其中内容变成了ES5的语法;
配置Vue
—项目使用Vuejs进行开发,而且会以特殊的文件来组织vue组件;因此需要在webpack环境中集成Vuejs;
—开发和运行都需要Vue,所以并不是开发时依赖:
npm install vue --save
—引入vue:
import Vue from 'vue'
—Vue两种不同版本:
(1)runtime-only:代码中不可以有任何的template;
(2)runtime-compiler:代码中可以有template,因为有compiler可以用于编译template;
—可以修改webpack.config.js进行配置,在module.exports中添加:
resolve:{ alias:{ //按照路径寻找文件 'vue$':'vue/dist/vue.esm.js' } }
正常运行之后,如果我们希望将data中的数据显示在界面中,必须修改index.html,如果后面自定义了组件,也必须修改index.html来使用组件;但是html模板在开发中不希望手动的频繁修改,可以定义
template
属性;!!!可以创建一个vue文件夹保存所有组件文件,通过
export default{}
导出,然后再入口文件中使用import App from './vue/app.js'
导入vue组件;—可以再vue文件夹下创建.vue文件,实现模板分离,可以将模块结构和组件js分离;然后再入口文件中进行引用:
import App from './vue/App.vue'
;但一定要记得配置.vue文件对应的loader:vue-loader
和vue-template-compiler
;安装以上两个loader并配置webpack.config.js文件;vue-loader
会有很多版本,因此可能会需要配置插件;—如果通过
import
引入文件时,后缀想要省略掉,可以再webpack.config.js中resolve
加入extensions:['.js','.css','.vue']
-
Webpack plugin
webpack中另外一个核心:plugin插件
—plugin插件通常对现有的某个框架进行扩展,webpack中的plugin就是对webpack现有功能进行各种扩展,比如打包优化、文件压缩等;
—loder和plugin区别:loader主要用于转换某些类型的模块,它是一个转化器(加载器);plugin是插件,对webpack本身的扩展,是一个扩展器;
—plugin的基本使用过程:
(1)通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装);
(2)在webpack.config.js中的plugins中配置插件;
添加版权的Plugin
—插件名称:
BannerPlugin
,属于webpack自带的插件;—因此不需要安装,可以直接通过修改webpack.config.js文件的配置:
const webpack = require('webpack') module.exports = { plugins:[ new webpack.BannerPlugin('最终版权归官方所有') ] }
—重新打包程序:查看bundle.js文件的头部,可以看到版权信息;
打包html的plugin
—在开发过程中,index.html文件是存放在项目的根目录下的,在真实发布项目时,发布的是dist文件夹的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件就没有意义了;所以需要将index.html文件打包到dist文件夹中,可以使用HTMLWebpackPlugin插件;
—该插件可以自动生成一个index.html文件(可以指定模板来生成),将打包的js文件自动通过
<script>
插入到body中;—该插件不是webpack中自带的,需要安装插件:
npm install html-webpack-plugin --save-dev
;—安装完毕后,使用插件,修改webpack.config.js中plugin部分的内容:
(1)这里的template表示根据什么模板来生成index.html;
(2)另外,需要删除之前在output中添加的publicPath属性,否则自动插入的script标签中的src可能会有问题;
const HtmlWeppackPlugin = require('html-webpack-plugin') plugins:[ new htmlWebpackPlugin({ template:'index.html' }) ]
js压缩的Plugin
—在项目发布之前,我们必然需要对js等文件进行压缩处理;
—我们可以使用第三方插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致:
npm install uglifyjs-webpack-plugin@1.1.1 --save-dev
;—修改webpack.config.js文件:
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin') module.exports = { plugins:[ new UglifyjsWebpackPlugin() ] }
—查看打包后的bunlde.js文件,是已经被压缩过的了;
搭建本地服务器
—webpack提供了一个可选的本地开发服务器,这个本地服务器基于node.js搭建,内部使用express框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果(先放入内存中,不会放在硬盘中);
—它是一个单独的模块,在webpack中使用之前需要先安装(安装版本最好和脚手架中webpack版本相对应):
npm install --save-dev webpack-dev-server@2.9.1
—修改webpack.config.js配置文件,修改如下:
module.exports = { devServer:{ //为哪一个文件夹提供本地服务,默认是根文件夹 contentBase:'./dist', //表示是否实时需要监听,实时刷新 inline:true //设置端口号,默认是8080 port:8080, //在SPA页面中依赖HTML5的history模式 historyApiFallback: } }
—运行命令时,不可以直接写入
webpack-dev-server
,因为没有在全局下安装,所以会报错;需要配置package.json文件,在执行脚本下添加"dev":"webpack-dev-server"
,然后使用npm run dev
就可以运行; -
配置文件分离
—开发和发布依赖不同的配置文件,可以将webpack.config.js分离成不同配置文件;
—然后可以通过
npm install webpack-merge --save-dev
进行配置文件的合并;—在需要合并的配置文件下,进行配置:
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin') const webpackMerge = require('webpack-merge') const baseConfig = require('./base.config') module.exports = webpackMerge(baseConfig,{ plugins:[ new UglifyjsWebpackPlugin() ] })
—分离后的配置文件,需要在package.json文件下执行脚本中修改配置文件的名称:
"build":"webpack --config ./build/prod.config.js"