随着前端技术的不断发展,项目的日趋复杂,为了实现代码复用及方便后期的项目维护,模块化在开发中变的必不可少.而目前更通用的是browserify、webpack等技术,是一种预编译模块的方案,而webpack相对于browserify更加强大,也是目前主流的自动模块化打包的工具,本次主要讲解webpack在前端模块化开发中的作用及实际的应用;
本文转自IT培训机构-学领未来
一、前端模块化规范介绍
1.1 CommonJS规范
CommonJS是适用于服务器端的,Node.js执行环境就是采用的CommonJS模式。它是同步加载不同模块文件,之所以采用同步,是因为模块文件都存放在服务器的各个硬盘上,实际的加载时间就是硬盘的文件读取时间。
(1) 一个单独的文件就是一个模块。每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性。
(2) 输出模块变量的最好方法是使用module.exports对象。
(3) 加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象。
1.2 AMD模块化规范
AMD是"Asynchronous Module Definition"的缩写表示"异步模块定义",由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数RequireJS,它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。
1.3 CMD模块化规范
CMD即Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个requireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和requireJS一样,只不过在模块定义方式和模块加载(可以说运行、解析)时机上有所不同。
二、Webpack基本介绍
2.1 Webpack介绍
Webpack是一个供浏览器环境使用的模块化打包工具,所有的静态资源都可以看成是一个个的小模块,模块之间可以相互依赖,而Webpack可以对这些依赖进行统一管理并打包发布,并将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求,它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用。如下图所示:
2.2 webpack的特点
1. 同时支持CommonJS和AMD模块,能够快速的迁移旧项目。
2. 串联式模块加载器及插件机制,具有更好的灵活性和扩展性,例如对CoffeeScript、ES 6的支持。
3. 可以基于配置或者智能分析打包成多个文件,实现分别满足公共模块和按需加载的需要,有效利用浏览器的缓存功能提升性能。
4. 将样式文件和图片等静态资源也可视为模块进行打包。配合loader加载器,可以支持sass,less等CSS预处理器,无须依靠grunt或gulp等构建工具,简化工程配置。
5. 开发时在内存中完成打包,性能更高,完全可以支持开发过程的实时打包需求。
6. 支持模块加载器和插件机制,可对模块灵活定制。特别是我最爱的babel-loader,有效支持ES6。
7. 内置有source map,即使打包在一起依旧方便调试。
三、Webpack在前端开发中的实际应用
3.1 基于webpack的前端开发环境搭建
1. 安装node.js,npm等工具,安装步骤不再一一说明
因为webpack基于commonJS的方式进行打包需要用到node.js的环境与npm包管理工具,用于管理与安装项目需要依赖的第三方库
2. 创建一个项目文件夹,并使用npm工具进行初始化
(1) 打开cmd执行npm init指令,用于初始化生成package.json文件
(2) 安装webpack,在项目目录下执行如下的指令
npm install webpack -g 表示全局安装
npm install webpack@版本号 --save-dev,使用--save-dev安装的插件,被写入到 devDependencies对象里面去,而使用--save安装的插件,则被写入到 dependencies 对象里面去。devDependencies里面的插件只用于开发环境,不用于生产环境,而dependencies是需要发布到生产环境的。
(3) 这里直接采用webpack命令进行文件打包的方式不再讲解,直接使用创建webpack.config.js配置webpack打包信息的方式,简单配置说明如下:
webpack.config.js配置信息如下 var path = require('path'); // 新版api要导入path包,用于获取文件绝对路径 module.exports={ entry:'./src/page/index.js', // 入口文件,需要打包的文件 output:{ // path:'./dist', // 老版本的API path:path.resolve(__dirname, 'dist'), // 新版本API filename:'[name].js' // name表示根据输入的文件名称进行输出 } } 此处需要注意,如果安装的是新版本的webpack,此处如果直接用path:' '的话会报如下错误,需要path.resolve(__dirname, 'dist'),dist为打包后输出的总目录 Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema. - configuration.output.path: The provided value "./dist" is not an absolute path! -> The output directory as **absolute path** (required). |
(4) webpack公共模块抽取CommonsChunckPlugin插件的使用
主要作用:有一个A模块被B,C,D三个模块引用,这个时候A模块就可以放入到公共的模块中,在webpack配置文件中加入如下配置信息
plugins: [ new webpack.optimize.CommonsChunkPlugin('common.js', ['index', 'login']) ] 参数common.js表示公共模块的文件名,后面的数组元素与entry一一对应,表示要提取这些模块中的公共模块 plugins: [ new webpack.optimize.CommonsChunkPlugin( name:'commons', filename:'js/base.js') ] |
(5) 安装和配置样式处理的loader
此种方式是js与css打包在一起,会出现样式延迟的现象,所以需要单独打包css并通过link的方式引入进来 2. 安装npm install [email protected] --save-dev (1)此时会出现如下问题: UNMET PEER DEPENDENCY 出现这个的时候,不要重新安装,只是提示我们当前不是最新版本,可以升级到最新版 (2)修改webpack.config.js var path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); module.exports={ entry:{ 'common':['./src/page/common/index.js'], 'index':['./src/page/index/index.js'], 'login':['./src/page/login/index.js'] }, output:{ // path:'./dist', path:path.resolve(__dirname, 'dist'), filename:'js/[name].js' }, externals:{ 'jquery':'window.jQuery' }, module: { loaders: [ { test: /\.css/, loader:ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader']}) } ] }, plugins: [ new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename:'js/base.js'}), new ExtractTextPlugin("css/[name].css") ] } (3)这时候出现打包错误 71% sealingF:\workspaceSet\vsc\blog-ng-tab\node_modules\webpack\lib\Chunk.js:34 throw new Error("Chunk.entry was removed. Use hasRuntime()"); 原因:extract-text-webpack-plugin官方针对webpack不同版本需要使用特定的版本 # for webpack 3 npm install --save-dev extract-text-webpack-plugin # for webpack 2 npm install --save-dev [email protected] # for webpack 1 npm install --save-dev [email protected] 解决方式:卸载之前的重新安装新的版本,卸载完毕需要看一下package.json中是否遗留了版本号,如果有先要删除 |
(6) 打包html的插件html-webpack-plugin
var path = require('path'); var webpack = require('webpack'); var ExtractTextPlugin = require('extract-text-webpack-plugin'); var htmlWebpackPlugin = require('html-webpack-plugin'); /** * 获取html-webpack-plugin参数的方法 * @param name * @returns {{filename: string, template: string, inject: boolean, hash: boolean, chunks: *[]}} */ var getHtmlConfig=function (name) { return { filename:'view/'+name+'.html', // 也可以指定htmnpml的名称filename:'js/[name].js' template:'./src/view/'+name+'.html', // inject指定引入文件的位置是头部还是body内部 inject:'body', hash:true, // 需要打包的模块,也就是需要将哪些js打包到对应的html中 chunks:['common',name] } }; var config={ entry:{ 'common':['./src/page/common/index.js'], 'index':['./src/page/index/index.js'], 'login':['./src/page/login/index.js'] }, output:{ // path:'./dist', path:path.resolve(__dirname, 'dist'), filename:'js/[name].js' }, externals:{ 'jquery':'window.jQuery' }, module: { loaders: [ { test: /\.css$/, loader:ExtractTextPlugin.extract({ fallback: 'style-loader', use: ['css-loader']}) } ] }, plugins: [ // 独立通用模块到js/base.js new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename:'js/base.js'}), // 打包css到单独的文件里 new ExtractTextPlugin("css/[name].css"), // html模板的处理 new htmlWebpackPlugin(getHtmlConfig('index')), new htmlWebpackPlugin(getHtmlConfig('login')) ] }; module.exports=config; |
(7) 安装html-loader用于抽取公共的html模板
html-head.html文件(公共的html模板)
引入头部文件 |
(8) 图片及文字处理
加入如下的loader设置,安装url-loader,file-loader(当文件大于100的时候会以文件的形式打包,所以需要安装此模块)
{ test: /\.(gif|png|jpg|woff|svg|eot|ttf)\??.*$/, // \??.*用于匹配带参数的图片 loader: 'url-loader?limit=100&name=resource/[name].[ext]' } |
至此,基本的webpack环境就已经搭建完毕了
四、总结
Webpack是一个自动化的前端构建工具,能够较大程度的提升前端开发效率及代码质量,让你在开发的时候能够以模块化的形式组织代码,而发布到生产环境中可以根据修改webpack的配置来实现依赖库的按需加载,代码压缩,less转换等等功能.