webpack、babel模块、模块化
一、webpack介绍
webpack这个工具非常强大。对前端中所有模块进行打包,输出js文件,后续引入这个js文件,在服务器上线,然后在域名中访问写好的项目;webpack还能支持模块化加载(类似python,import xxx from 'ooo')。中文官网链接地址:https://www.webpackjs.com/
1、为什么要使用webpack
现今的很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法。
- 模块化,让我们可以把复杂的程序细化为小的文件。
- 类似TypeScript这种在JavaScript基础上拓展的开发语言:使我们能实现目前版本JavaScript不能直接使用的特性,并且之后还能转换为JavaScript文件使浏览器可以识别。
- Scss、less等CSS预处理器
这些改进确实大大提高了开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,手动处理非常繁琐,WebPack类的工具的出现就是为了解决这样的需求。
2、什么是webpack
webpack 是一个现代 JavaScript 应用程序的 静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个 依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
3、WebPack与Grunt及Gulp特性对比
Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具。
Grunt和Gulp的工作方式是:在一个配置文件中,指明对某些文件进行类似编译,组合,压缩等任务的具体步骤,工具之后可以自动替你完成这些任务。
Webpack的工作方式:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到你的项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
如果要将二者进行比较,Webpack的处理速度更快更直接,能打包更多不同类型的文件。
二、babel
这个是解析我们es6的代码的,为什么要用它呢,因为对于一些ie浏览器,甚至FF浏览器,低版本的还不能识别我们的es6代码,那么vue里面好多还让我们去写es6的代码,这个时候我们就可以用babel这个工具将我们的es6的代码转译成浏览器能识别的代码.
左边是我们写的es6代码,右边是通过babel这个工具编译之后的代码。这个代码能在我们各个浏览器中去识别。
所以babel是用于编写下一代JavaScript的编译器。
三、前端中模块
在前端中一个js文件就是一个模块,在js中没有模块化的概念。
webpack:对前端中的资源编译打包、支持模块化es6的Model。
在webpack中,所有类型的文件都可以是模块,包括Javascript、CSS、图片、JSON。通过加载器(Loader)将JavaScript 的模块推广到其他类型文件。
1、历史介绍
(1)2009年初,commonjs规范还未出来,此时前端开发人员编写的代码都是非模块化的,
那个时候开发人员经常需要十分留意文件加载顺序所带来的依赖问题
(2)与此同时 nodejs 开启了js全栈大门,而 requirejs 在国外也带动着前端逐步实现模块化
同时国内 seajs(海纳百川 有容乃大)也进行了大力推广
AMD 规范 ,具体实现是:requirejs define('模块id',[模块依赖1,模块依赖2],function(){ return ;}) , ajax请求文件并加载
Commonjs || CMD 规范seajs 淘宝玉伯
commonjs和cmd非常相似的
cmd require/module.exports
commonjs是js在后端语言的规范: 模块、文件操作、操作系统底层
CMD 仅仅是模块定义
UMD 通用模块定义,一种既能兼容amd也能兼容commonjs 也能兼容浏览器环境运行的万能代码
(3)npm/bower集中包管理的方式备受青睐,12年browserify/webpack诞生
npm 是可以下载前后端的js代码475000个包
bower 只能下载前端的js代码,bower 在下载bootstrap的时候会自动的下载jquery
browserify 解决让require可以运行在浏览器,分析require的关系,组装代码
webpack 打包工具,占市场主流
(4)es6的module
export default {} || fn || msg,前端中也是有模块的,导入方式是下面这种用法。
import xxx from './index.js'
es6Module 支持import(导入)和export(导出)。跟python的import很像。但它必须在服务器环境下才支持,或者我们可能通过webpack的babel-loader将es6支持转化成es6的语言。
2、webpack下载
# 下载webpack,-g代表全局 $ npm i webpack@3.12.0 -g # 查看webpack $ webpack -v 3.12.0
3、webpack的基本使用
在webpack-demo 目录中新建index.html文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模块的基本使用</title> </head> <body> <!--<script type="text/javascript" src="App.js"></script>--> <!--<script type="text/javascript" src="main.js"></script>--> <script type="text/javascript" src="bundle.js"></script> </body> </html>
创建App.js文件:
// es6 module export抛出 import导入 let obj = { name: 'alex' }; export default obj; let age = 23; export {age}; // 作为一个key抛出 export var fav = "鸡汤"; export function add() { console.log('弹出了') }
创建main.js文件:
import app from './App.js' console.log(app); import {age, fav, add} from './App.js' console.log(age); console.log(fav); add();
使用webpack将main.js 打包成 bundle.js文件:
$ webpack ./main.js ./bundle.js Hash: 9f8da91e23bd4d667df5 Version: webpack 3.12.0 Time: 96ms Asset Size Chunks Chunk Names bundle.js 3.54 kB 0 [emitted] main [0] ./App.js 186 bytes {0} [built] [1] ./main.js 128 bytes {0} [built]
查看浏览器conosle输出:
4、main.js简写
将main.js的内容做如下简写:
import * as o from './App.js' console.log(o);
再次将index.js进行打包:
$ webpack ./main.js ./bundle.js
查看页面输出,作为整个对象抛出,如下所示:
5、webpack引入vue
创建index.html内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模块的基本使用</title> </head> <body> <div id="app"></div> <script type="text/javascript" src="bundle.js"></script> </body> </html>
创建App.js内容如下:
// es6 module export抛出 import导入 let App = { template: ` <div> 我是一个App组件 </div> ` }; export default App; let age = 23; export {age}; // 作为一个key抛出 export var fav = "鸡汤"; export function add() { console.log('弹出了') }
创建main.js内容如下,引入vue.js文件:
import * as o from './App.js' console.log(o); import Vue from './vue.js' // 引入Vue模块 new Vue({ el: '#app', data(){ return { } }, template:` <App/> `, components: { App:o.default } })
执行webpack,将main.js 打包成 bundle.js文件:
$ webpack ./main.js ./bundle.js Hash: b8b29cf57e405a8f2ee4 Version: webpack 3.12.0 Time: 645ms Asset Size Chunks Chunk Names bundle.js 309 kB 0 [emitted] [big] main [0] (webpack)/buildin/global.js 509 bytes {0} [built] [1] ./main.js 396 bytes {0} [built] [2] ./App.js 257 bytes {0} [built] [3] ./vue.js 289 kB {0} [built]
显示效果如下所示:
四、webpack配置文件使用示例
webpack.config.js这个配置文件文件名是webpack默认的配置文件文件名。
1、初始化项目
首先进入项目目录webpack_demo(最近父目录不能是中文)并完成初始化项目:
$ npm init --yes
项目初始化完成后,目录中多出package.json文件,内容如下所示:
{ "name": "webpack_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }
2、安装webpack
在webpack_demo项目根目录中安装 webpack:
$ npm i webpack@3.12.0 -D
上例中指定了 webpack 版本号,如果下载时没有指定,安装完成后可以看到当前安装的webpack版本号。
3、webpack配置文件
由于配置插件越多命令行会越长(webpack ./main.js ./bundle.js),此时,可以将命令行参数移入webpack配置文件。
新建一个 webpack.config.js 文件:
module.exports = { // entry入口 entry: { main: './main.js' }, // output出口 output: { filename: './bundle.js' } }
4、HTML、Javascript文件构建
index.html:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模块的基本使用</title> </head> <body> <div id="app"></div> <!--<script type="text/javascript" src="App.js"></script>--> <!--<script type="text/javascript" src="main.js"></script>--> <script type="text/javascript" src="bundle.js"></script> </body> </html>
javascript文件:
// App.js let App = { template: ` <div> 我是一个App组件 </div> ` }; export default App; let age = 23; export {age}; // 作为一个key抛出 export var fav = "鸡汤"; export function add() { console.log('弹出了') } // main.js import * as o from './App.js' console.log(o); import Vue from './vue.js' // 引入Vue模块 new Vue({ el: '#app', data(){ return { } }, template:` <App/> `, components: { App:o.default } })
5、执行打包
$ webpack
执行打包后,查看页面显示效果:
6、修改默认配置文件文件名
由于在日常使用中,常常分有开发环境和生成环境。在生产环境下希望配置有watch,能够去自动编译。但在开发环境下,则不需要有watch,打包完成后退出即可。
在这里复制两份webpack.config.js文件分别命名为:webpack.dev.config.js、webpack.prod.config.js。
然后需要配置package.json文件,让它能够识别这两个新的js文件:
{ "name": "webpack_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.prod.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^3.12.0" } }
执行npm run dev/build 来分别给生产环境和开发环境打包:
$ npm run dev $ npm run build
五、webpack加载 CSS 文件
在上面的webpack_demo项目中没有添加css样式。如果要添加css样式,一个是可以直接写在标签的 style 属性中。
再就是可以写在css文件中,在目录中新增main.css文件:
body{ background-color: red; }
然后在main.js中引入应用:
import * as o from './App.js' import Vue from './vue.js' // 引入Vue模块 // 导入css import './main.css' new Vue({ el: '#app', data(){ return { } }, template:` <App/> `, components: { App:o.default } })
此时执行npm run dev,就会发现报错如下所示:
Version: webpack 3.12.0 Time: 670ms Asset Size Chunks Chunk Names ./bundle.js 309 kB 0 [emitted] [big] main [0] (webpack)/buildin/global.js 509 bytes {0} [built] [1] ./main.js 409 bytes {0} [built] [2] ./App.js 257 bytes {0} [built] [3] ./vue.js 289 kB {0} [built] [7] ./main.css 169 bytes {0} [built] [failed] [1 error] + 3 hidden modules ERROR in ./main.css Module parse failed: Unexpected token (1:4) You may need an appropriate loader to handle this file type. | body{ | background-color: red; | } @ ./main.js 12:0-19
- css-loader - 预处理 CSS 文件
- style-loader - 将 CSS 插入到 DOM 中的
style
标签
需要注意的是:如果只使用了 css-loader,则 webpack 只是将CSS文件预处理成模块然后打包到构建文件中,并不会插入到页面(这是 style-loader 的作用)。
1、安装CSS加载器
$ npm install css-loader -D;
$ npm install style-loader -D
下载完成后,可以看到package.json中多了这两个组件:
{ "name": "webpack_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.prod.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "style-loader": "^0.23.1", "webpack": "^3.12.0" } }
2、修改webpack.config.js配置
修改配置让webpack识别这两个loader :
module.exports = { // entry入口 entry: { main: './main.js' }, // output出口 output: { filename: './bundle.js' }, watch:true, // 模块中的loader,loader加载器能对css、json、png、jpg、mp3、mp4、es6的js代码解析 module:{ loaders:[ { test:/\.css$/, // css结尾的 loader:'style-loader!css-loader' // 依次识别 } ] } }
需要注意的是,loader的顺序非常重要,加载器的执行顺序是从后往前的,如果把 sytle-loader 放在 css-loader 后面,style-loader 是无法理解CSS文件的,需要先经过 css-loader 预处理。
3、打包及查看效果
在完成项目开发后,将输出文件打包:
$ npm run dev > webpack_demo@1.0.0 dev /Users/.../webpack_demo > webpack --config ./webpack.dev.config.js Hash: 45b4436bff4c76fd3bc8 Version: webpack 3.12.0 Time: 1142ms Asset Size Chunks Chunk Names ./bundle.js 326 kB 0 [emitted] [big] main [0] (webpack)/buildin/global.js 509 bytes {0} [built] [1] ./main.js 409 bytes {0} [built] [2] ./App.js 257 bytes {0} [built] [3] ./vue.js 289 kB {0} [built] [7] ./main.css 1.07 kB {0} [built] [8] ./node_modules/css-loader/dist/cjs.js!./main.css 1
显示效果:
六、webpack插件
1、html-webpack-plugin插件介绍
该插件将为您生成一个HTML5文件,其中包含使用script
标记在正文中的所有webpack包。
(1)该插件主要有两个主要作用:
- 为html文件中引入的外部资源如 script、link 动态添加每次complie后的hash,防止引用缓存的外部文件问题。
- 可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个 html-webpack-plugin 可以生成N个页面入口。
(2)插件生成html文件的原理:
将 webpack中 entry 配置的相关入口 chunk 和 extract-text-webpack-plugin 抽取的css样式 插入到该插件提供的 template 或者 templateContent 配置项指定的内容基础上生成一个html文件,具体插入方式是将样式 link 插入到 head 元素中,script 插入到 head 或者 body 中。
2、构建新项目
(1)src目录内容构建
创建src目录后,创建编辑如下文件:
App.js文件:
// es6 module export抛出 import导入 var App = { template: `<div>{{msg}}</div>`, data(){ return { msg: "我们学习module 哈哈哈哈 更改了数据" } } }; // 先抛出 export default App;
main.js文件:
import Vue from './vue.js' // 引入Vue模块 import App from './App.js' // 导入css import './main.css' new Vue({ el: '#app', data(){ return { } }, template:` <App/> `, components: { App } })
main.css文件:
body{ background-color: red; }
还在src引入vue.js文件:
npm install vue -S
(2)构建根目录和dist目录
在根目录中构建各种配置文件:package.json、wabpack.conf.js、wabpack.dev.conf.js、wabpack.prod.conf.js。
在根目录中构建index.html模板文件:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模块的基本使用</title> </head> <body> <div id="app"></div> </body> </html>
在根目录创建dist目录。distdistsd
3、html-webpack-plugin插件使用
(1)插件安装
$ npm install html-webpack-plugin -D
(2)引入插件
调整webpack.config.js配置文件,将插件添加到webpack配置中:
// node.js中内容模块 var path = require('path'); var HtmlWebpackPlugin = require('html-webpack-plugin'); // html-webpack-plugin module.exports = { // entry入口 entry: { main: './src/main.js' }, // output出口 output: { path:path.resolve('./dist'), // 相对转绝对 filename: './bundle.js' }, watch:true, // 模块中的loader module:{ loaders:[ { test:/\.css$/, // css结尾的 loader:'style-loader!css-loader' // 依次识别 } ] }, // 插件 plugins:[ new HtmlWebpackPlugin({ template: './index.html', // 参照模板,以这个文件为参照物生成到dist目录 }) ] }
注意作为模板参照的index.html里去除之前bundle.js的引入。
3、为环境打包
执行npm run dev/build 来分别给生产环境和开发环境打包
$ npm run build
执行完成后,可以看到dist目录下多出了两个文件:bundle.js 和 index.html。具体index.html内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模块的基本使用</title> </head> <body> <div id="app"></div> <script type="text/javascript" src="./bundle.js"></script></body> </html>
显示效果如下所示:
4、使用http-server测试上线
安装http-server(必须要有node和npm):
$ npm install -g http-server
启动服务:
找到你的文件夹,在当前文件夹下打开命令行,输入http-server,默认启动是8080端口。
$ hs -o -p 8890
自动打开浏览器显示效果如下所示:
七、webpack-dev-server介绍
webpack 提供 webpack-dev-server 来解决自动刷新浏览器的问题。它是一个基于 expressjs的开发服务器,提供实时刷新浏览器页面的功能。
1、安装webpack-dev-server
在项目下安装 webpack-dev-server:
$ npm install webpack-dev-server -D
下载完成后package.json中出现对应信息:
{ "name": "webpack_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.prod.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "webpack": "^3.12.0", "webpack-dev-server": "^3.3.1" } }
在这个版本下,运行 npm run dev 需要有 webpack-cli。老版本则不需要:
$ npm install webpack-dev-server@2.9.0 -D
执行后修改 package.json内容如下所示:
"devDependencies": { "css-loader": "^2.1.1", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "webpack": "^3.12.0", "webpack-dev-server": "^2.9.0" } }
2、修改package.json脚本配置
--hot:热承载,页面数据修改自动刷新
--open:自动打开网页
{ "name": "webpack_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "webpack-dev-server --open --hot --inline --config ./webpack.dev.config.js", "build": "webpack --config ./webpack.prod.config.js" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "css-loader": "^2.1.1", "html-webpack-plugin": "^3.2.0", "style-loader": "^0.23.1", "webpack": "^3.12.0", "webpack-dev-server": "^2.9.0" } }
此时执行如下命令,会自动在浏览器打开 http://localhost:8080页面
$ npm run dev
修改App.js中内容保存后,页面显示自动刷新。