webpack与SPA实践之开发环境搭建
栏目: JavaScript · 发布时间: 6年前
内容简介:webpack与SPA实践之开发环境搭建
目前,公司前端项目开发技术栈基本改造为使用gulp进行自动化构建,webpack进行项目模块化依赖管理,Vue+ Vuex + Vue-Router作为项目组件化开发框架,为了更深入的理解、使用当前技术栈并与读者分享、交流,计划推出一系列相关学习与实践文章。本篇为开篇,主要讲述如何使用webpack搭建开发环境。
项目初始化
以你喜欢的任意方式,创建项目根目录,如:
mkdir vue-hello
初始化包模块管理文件
进入项目根目录,初始化项目包模块管理文件package.json:
npm init
命令台会提示你输入一堆信息,如果你想简单一点,可以添加 -y
参数,跳过输入步骤,生成默认信息:
npm init -y
初始化源码目录
在项目根目录下创建源码目录结构,通常源码目录是src或app,个人喜好是使用src:
webpack简述及使用
虽然在本篇文章我们不会对webpack做太过详细的介绍,但是依然希望能帮助读者对webpack拥有更清晰的了解,webpack是什么?
webpack is a tool to build JavaScript modules in your application
webpack是一个帮助你的应用构建JavaScript模块的工具。
接下来,我们介绍几个知识点帮助理解webpack:模块化,webpack原理及其与grunt和gulp的比较。
模块化
模块化指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程。
模块是一个可组合、分解和更换的单元,将一个系统 分解 成若干模块,单元;大家遵循一定的规范,各司其职,各自开发不同模块;之后可以较低成本的将模块 组合 起来,构成一个完整的系统,极大方便了团队成员之间的协助开发,产出效率得到有效提升。
webpack原理
webpack是一个帮助你的应用构建JavaScript模块的工具,其本质只能处理JavaScript,那你会疑惑了,不是说使用webpack,可以很方便的在JavaScript代码中引用图片,CSS等资源嘛?是的,这正是webpack的优势,那怎么实现的呢?这就要涉及到webpack中的一个概念: 加载器(loader) 。
加载器是作用于应用资源文件的转换器,它们是一系列JavaScript函数,接受资源文件的内容做参数,然后返回新的资源(以一个JavaScript模块的形式返回)。
所以,对于webpack,我们明确三点:
- 模块 :webpack中一切资源文件(JavaScript, 样式, 图片资源等)皆视为模块;
- 加载器 :webpack通过加载器(JavaScript函数)将其他资源处理(构建)成JavaScript模块;
- 管理依赖 :webpack在编译模块时,就能分析查找该模块内的依赖,可以很好的处理不同模块间的依赖;
webpack对比grunt/gulp
-
grunt
打开grunt官网,你可以看到最醒目的介绍:
The JavaScript Task Runner
,还有一个关键字automation
– 自动化,其定位是一个JavaScript的自动化构建任务处理器,帮助开发者自动化处理项目的构建流程; -
gulp
gulp官网的定义是:
Automate and enhance your workflow
,自动强化项目构建流程,其与grunt的目标一致,都是帮助开发者自动化处理项目的构建流程,不同的是gulp实现方式是基于流的,即以流的方式处理文件,而grunt是以二进制方式处理文件,gulp使用性能是要强于grunt的; -
总结
- webpack定位是一个模块化管理工具,而grunt/gulp都是自动化任务流程构建工具;
- grunt基于二进制处理文件,gulp基于流式处理文件,效率比grunt更高一些;
- webpack强大特性,使得其添加诸多插件可以替代grunt/gulp,但是目前的实践项目中,通常webpack结合gulp或grunt使用(各自处理各自专长的任务);
安装
首先安装webpack,npm或yarn都可以,无甚区别:
npm install --save-dev webpack
关于此处的 --save
和 -dev
参数做简要说明:
-
--save
是声明将安装依赖添加入package.json文件; - 默认地,使用npm安装包模块依赖时,依赖关系存储在在
"dependencies"
属性对象内,表示项目依赖; - webpack是作为开发环境依赖的,不是作为源码直接调用,所以添加
-dev
参数,以声明其是开发环境依赖;
webpack配置介绍
实践项目使用webpack完成自动化构建,本地服务调试与热加载,首先在根目录下创建webpack的配置入口文件webpack.config.js,基本内容结构如下:
var path = require('path'); module.exports = { context: path.resolve(__dirname, 'src/'), entry: { app: './scripts/app.js' }, output: { filename: '[name].js', path: path.resolve(__dirname, 'dist/scripts/') }, module: { loaders: [] }, resolve: { modules:[], alias: {}, extensions: [] }, plugins: [], devServer: {} };
如上,webpack配置文件使用module.exports方式导出配置对象,webpack执行时会默认读取项目根目录下webpack.config.js文件,当然可以手动配置指定一个文件作为配置文件,我们不讨论,可以参考webpack文档,接下来对webpack配置内容做简要介绍,如果你对webpack使用比较熟悉,可以跳过此节。
文件处理配置
和webpack文件处理相关的几个配置属性主要有三个:目录上下文信息(context), 处理文件入口信息(entry), 文件输出信息(output)。
目录上下文信息(context)
设置解析处理文件入口的相对目录,值为一个绝对目录路径,默认为当前执行目录,通常即项目根目录,在Node中其值与 process.cwd()
相同,如:
context: path.resolve(__dirname, 'src/'),
如上即解析为项目根目录下的src目录。
处理文件入口信息(entry)
处理文件入口,值可以是字符串,或数组,或对象,值为字符串或数组时,即输出单文件,值为对象,可以输出多文件,输出文件名称等信息参考文件输出信息(output)。
文件输出信息(output)
此配置声明webpack编译输出文件的文件名等信息,如:
filename: '[name].js',
声明文件名就是模块(chunk)名,对应在entry中定义的入口,你可能还见过 [id]
, [hash]
, [chunkhash]
这些用法,现做简单介绍:
- [id] :该值表示webpack编译模块(chunk)的id,通常是一个数字;
- [name] :该值表示webpack编译模块(chunk)名,对应entry中定义的入口名或文件名;
- [chunkhash] :该值表示webpack编译模块(chunk)hash值,根据模块内容计算出的一个md5值;
- [hash] :该值表示webapck编译对象hash值,根据编译对象计算出的md5值;
编译对象,即webpack执行时读取配置后生成的一个编译配置对象,包含模块,待编译文件,相对于上次编译的变更文件等诸多信息,需要注意的是该对象在webpack启动读取配置文件后形成,在此次编译过程保持不变。
- output.path:定义输出文件所在目录;
- output.publicPath:定义输出文件在浏览器访问时的基础相对路径,可以与后文
webpack-dev-server
一起使用。
webpack加载器与模块
在介绍加载器配置之前,先看看加载器是什么:
Loaders are transformations that are applied on a resource file of your app. They are functions (running in node.js) that take the source of a resource file as the parameter and return the new source.
加载器是作用于应用资源文件的转换器,它们是一系列函数,接受资源文件的内容做参数,然后返回新的资源(以一个模块的形式返回)。
webpack
webpack解析文件时使用的加载器都声明在 module
属性的 loaders
数组中,可以设置一个或多个加载器。
- module.noParse:指定某些文件不需要使用解析,支持传入文件路径或正则表达式;
- module.loaders:指定解析文件的加载器模块及各模块解析规则,可以设置以下属性:
-
test
: 待解析文件需匹配的规则,通常以文件后缀名称匹配文件; -
include
:待解析文件所处目录; -
exclude
: 过滤掉的目录; -
loader
:加载器模块名称; -
loaders
多个加载器;
-
模块解析规则配置
webpack支持在 resolve
属性对象中配置模块解析规则,主要有 root
, modules
, alias
和 extensions
属性。
resolve.root与resolve.modules
该属性设置的是在开发代码中使用 require
或 import
加载某模块时,webpack查找该模块所遵循的查找目录范围,如在源代码中存在:
var utils = require('utils/utils.js');
而 root
配置如下:
resolve: { root: [ path.resolve('./src/'), 'node_modules' ] }
webpack编译时将自动在项目根目录下的 src
目录内的 utils
目录下查找 utils.js
,若存在,则返回,否则进入 node_modules
目录内查找 utils.js
模块。
当然,若未设置 resolve.root
属性值,则webpack默认先从 node_modules
查找模块,然后在根目录下查找。
注意:resolve.root在webpack v1版本中使用,而在webpack v2 中,使用modules代替,建议使用v2版本,后文也将统一使用modules属性。
resolve.alias
alias,有别名的意思,这里的作用是设置其他模块或路径的别名,webpack在解析模块时,将使用配置值替换该别名,如,在未设置alias属性内容时,即resolve.alias默认是空对象 {}
时,我们在代码中引用模块:
var Vue = require('vue/dist/vue.js'); var TopHeader = require('components/header.js');
webpack在编译代码时,按 resolve.modules
声明的顺序依次查找对应模块,如按照上一节定义的 resolve.modules
:
resolve: { root: [ path.resolve('./src/'), 'node_modules' ] }
查找模块时,将首先在 src/vue/dist/
目录下寻找 vue
模块,在 src/components/
目录下查找 header.js
模块,查找到后返回,否则进入 node_modules
目录查找。
现在,我们还可以通过 resolve.alias
为模块或路径声明一个别名,更方便的声明加载模块:
resolve: { alias: { 'vue$': 'vue/dist/vue.js' components: path.resolve(__dirname, 'src/components/') } }
我可以使用如下方式加载模块:
var Vue = require('vue'); var TopHeader = require('components/header.js');
-
$
符号
关于 alias
的详细使用介绍,请 参见文档 ,本文并不是要介绍webpack文档,在这里介绍一下声明的 vue$
别名中的 $
符号:
这里的 $
符合是正则的文末匹配符,即只有当 vue
是最后一级路径时,webpack才会将该值解析成别名,进行别名与对应值替换,如 vue/test.js
中的vue是不会当作别名解析的,而 components/header.js
中的components则会按照声明的 components
别名进行解析,其结果是 src/components/header.js
。
resolve.extensions
该值定义解析模块时的查找文件的后缀顺序,如 ["", ".js", ".json"]
,会优先返回js文件,其次json文件,然后是其他文件,注意,这里数组传入了一个空字符串,他的作用是在未找到配置中所有列举的类型文件时,支持webpack返回其他类型文件。
webpack插件配置
webpack还支持多种多样的插件拓展,你可以使用它们对你的项目webpack模块构建过程进行额外处理,如代码压缩,图片等资源提交压缩,构建异常捕获和提升,构建流程时间消耗比,等等,而关于这些插件使用的配置在 plugins
属性数组内,将在后续进行介绍。
项目本地调试与开发
为了方便开发和调试,通常都需要在本地主机开启服务,提供局域网内多终端访问,并且在文件变更时,实时刷新页面,正如grunt和gulp中 Browsersync
插件提供的功能一样,webpack可以使用 webpack-dev-server
模块实现。
webpack-dev-server是一个Node.js的express服务器,以webpack开发中间件的形式为webpack包提供服务,当监听到源码文件变更时,会自动重新打包,并且支持配置自动刷新浏览器,重新加载资源。
安装
由于该插件只用于开发模式,所以通过以下npm指令安装:
npm install webpack-dev-server --save-dev
配置
启用 webpack-dev-server
时,其默认开启8080端口,访问 localhost:8080
返回当前目录下的 index.html
,即执行指令当前目录下的静态资源,当然可以通过指令传递参数或在配置文件进行配置指定静态资源目录。
另外需要注意的是,开启 webpack-dev-server
后,变更文件重新打包后,并不会实际输出到配置的 output
目录,而是在 publicPath
属性声明的相对路径所在的内存中读取。
静态资源目录配置(content base)
webpack-dev-server --content-base src/
执行以上指令开启服务后, webpack-dev-server
将默认在 src/
目录返回静态资源,当然也可以在 webpack.config.js
配置文件中指定:
devServer: { contentBase: './src' }
访问 http://localhost:8080
和 http://localhost:8080/index.html
效果一样,均返回 src
目录下的 index.html
文件。
publicPath与输出文件访问
在前文webpack配置一节中提到 output.publicPath
属性值表示,在浏览器访问 webpack output
输出的文件时的基础相对路径,如设置:
output: { path: 'dist/scripts', filename: 'app.js', publicPath: 'assets/' }
则在html文件中引用该 app.js
文件的方式如下:
<script src="assets/app.js"></script>
在浏览器中访问 app.js
的方式为: http://localhost:8080/assets/app.js
自动刷新(Automatic Refresh)
前面说到 webpack-dev-server
支持文件变更时,自动刷新浏览器,这也是开发者急需的功能, webpack-dev-server
支持两种方式实现:
-
iframe
模式(iframe mode):页面通过iframe
窗口插入然后变更时自动重新加载; -
inline
模式(inline mode):通过sock.js(比如websocket协议,轮询等方式)在页面嵌入一个小型客户端与webpack-dev-server
服务器建立连接,当发生变更重新打包时,通过此连接通知页面重新加载;
iframe模式
使用默认的 iframe
模式时,不需要进行任何配置,可以直接访问: http://localhost:8080/webpack-dev-server/index.html
即可,如图,通过 iframe
插入我们的页面:
注意:
- 在应用页面上方会有状态栏显示当前应用信息;
- 应用URL的变更发生在
iframe
内部,不会反映在浏览器地址栏;
inline模式
要开启 inline
模式,只需要指定 --inline
命令行参数或在配置文件中指定 inline: true
:
devServer: { contentBase: './src', inline: true }
在此模式下,直接访问 http://localhost:8080/index.html
或 http://localhost:8080
即可,此模式与 iframe
模式的区别在于:
- 访问URL不同;
- 需指定
inline
配置参数; - 应用信息在控制台输出;
- 应用URL的变更直接反映在浏览器地址栏;
其实 inline
模式还可以配合Node.Js服务运行,之后再介绍,这里只说明了其在HTML文档中的使用。
热替换(Hot Module Replacement)
除了自动刷新, webpack-dev-server
的另一大卖点是模块热替换,那么热替换到底是什么?
热替换,即文件发生变更时,webpack包只替换发生变更的模块,而不需要全部替换;浏览器不需要完全重新加载,而可以直接将变更的模块注入到运行中的应用。
开启热替换功能需要指定 --hot
指令参数,或在配置文件中添加:
devServer: { contentBase: './src', inline: true, hot: true }
注意到以上代码,热替换需要与 inline
模式一起使用,另外需要指定 output.publicPath
值。
HotModuleReplacementPlugin
配置好后还需要使用 webpack.HotModuleReplacementPlugin
插件,才能真正启用热替换功能:
plugins: [ new webpack.HotModuleReplacementPlugin() ]
同样的,热替换可以搭配Node.js服务一起使用,之后介绍。
如图,为每个文件(app.js, test.js)都实现了HMR热替换,当发生变更时,只更新变更模块,而不是重新加载所有文件:
拥抱ES6
ES6推出以来,广受Jser们青睐,其确实有很多新特性和新规范,值得我们深入学习并使用,可以参考ECMAScript 6入门,未来所有的JavaScript应用都应该拥抱ES6,不过,目前各大浏览器都在推进ES6的实现,在兼容实现之前,我们还需要过渡性的将其转换成ES5语法,最通用的方式就是使用 babel
转换。
使用babel加载器
首先,为了能使用webpack和babel转换js代码,需要使用 babel-loader
加载器,另外还需要安装 babel
转换js的转换规则插件,如 babel-preset-es2015
定义了转换规则,安装方式如下:
npm install --save-dev babel-loader babel-preset-es2015
然后在根目录下创建 .babelrc
文件,内容:
{ "presets": ["es2015"] }
在webpack.config.js配置文件中,添加相关loader配置:
module: { loaders: [ { test: /\.(js|vue)$/, exclude: /node_modules/, loader: 'babel-loader' } ] }
其中, test
匹配需要转换的文件, exclude
匹配不需要转换的文件或目录。
到此,基本介绍了如何使用webpack搭建开发环境,下一篇将开始介绍如何使用webpack处理CSS及如何使用Vue进行组件化开发。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 实践Substrate私有网络搭建
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
- Kafka从上手到实践-实践真知:搭建单机Kafka
- (全栈学习实践)四、docker搭建redis主从实践
- (全栈学习实践)四、继续搭建集群
- Netty搭建TCP服务器实践
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。