这是别眨眼学前端的第 003 篇文章,别眨眼系列文章的主旨在于能够快速的回顾某个库/框架或是某种编程语言的基本知识点,于我而言作用类似于详细一点的复习大纲,用于快速回顾记忆,标题命名来源于 苹果 的视频 Don't blink
这一篇我们来快速回顾一下 Webpack,本文是基于 Webpack — The Confusing Parts 学习编写而成,可能会有描述不够清楚的地方,可自行参考原文
其余别眨眼系列文章,可以查看以下链接,
Webpack 是在 React 或 Redux 应用中最常见的模块管理工具,然而第一眼看 Webpack 的配置文件时,却感觉非常难懂,因为 Webpack 使用了自创的语法以及拥有独特的核心理念,下面我们会对 Webpack 的核心理念和基本语法进行快速回顾,
Webpack 的核心理念
Webpack 拥有两条核心理念,
一切皆为模块,不单单 JS 文件可以是“模块”,其余任何 (CSS, HTML, 图像) 文件皆可成为模块。因此你可以这样
require('myJSfile.js')
或这样require('myCSSfile.css')
的引入我们需要的任何东西,这也意味着我们能够将任何文件分割成可管理的片段,并进行复用等,只在我们需要的时候加载需要的东西 (Load only “what” you need and “when” you need),通常的模块管理会将所有模块打包至一个单独的文件,
bundle.js
,但是在实际的应用中,可能这个文件会非常的大!所以 Webpack 拥有很多特性来支持你拆分你的代码 (split your code) 并生成多个bundle
文件,并且可以异步的加载所需的不同部分
接下来我们来看一下 Webpack 的一些基本语法,也是容易混淆的一些部分,
开发环境 Vs 生产环境 (Development Vs Production)
在 Webpack 众多特性中,一些适用于开发环境的 (Development-only) ,一些适用于生产环境 (Production-only),一些是二者皆可,
// example
output: {
// Dev
publicPath: '/'
// Production
publicPath: 'http://someCDN.com'
},
plugins: {
// Dev
new webpack.HotModuleReplacementPlugin(),
// Production
new AppCachePlugin({
exclude: ['.htaccess']
}),
new webpack.optimize.UglifyJsPlugin()
}
通常来讲,很多项目会在不同的环境下使用不同的 Webpack 特性,因此往往会配置两个配置文件
'scritps': {
// 生产环境
'build': 'webpack --config webpack.config.prod.js',
// 开发环境
'dev': 'webpack-dev-server'
}
webpack CLI Vs webpack-dev-server
Webpack 拥有两种交互接口,
Webpack CLI 工具 -- 默认的操作接口,随着 Webpack 默认一起安装,
webpack-dev-server 工具 -- 一个基于
Node.js
的服务器,必须单独安装
Webpack-dev-server (更加适用于开发环境)
Webpack-dev-server
默认使用 8080
端口,它能够提供比如 “实时更新 (Live Reloding)” 或者 ”热替换 (Hot Module Replacement)” 等功能,
// 安装
npm install webpack-dev-server --save
// 在终端中使用
webpack-dev-server --inline-hot
// 在 `package.json` 中使用
'scripts': {
'start': 'webpack-dev-server -inline --hot',
}
// 然后执行该脚本
npm start
// 在浏览器中访问
http://loacalhost:808
当然你可以使用两种方式去配置 wbpack-dev-server ,
在
webpack.config.js
中使用devServer
对象来配置,直接在命令行中输入
// 通过命令行
webpack-dev-server --hot --inline
// 通过 `webpack.config.js`
devServer: {
inline: true,
hot: true
}
hot
Vs inline
inline
选项为整个页面提供了 "实时更新" 功能,而 hot
则提供了 “热替换” 功能,用于尝试仅更新改变的组件,而非整个页面。当我们同时开启两个功能的时候,当源文件发生改变,webpack-dev-server 首先会尝试热替换,当热替换无法工作的时候,才会刷新整个页面
'entry' -- 字符串 Vs 数组 Vs 对象
Entry
告知 Webpack 根模块或是入口文件在哪里,它的值可以是字符串,数组或者对象,
// string
entry: '.publish/src/index.js'
// array
entry: ['.publish/src/index.js']
// object
entry: {'.publish/src/index.js'}
如果只有单一的入口文件,上述三种写法的结果是一样的,
entry -- 数组
当我们想要加入几个不相互依赖的文件的时候,即可使用数组格式,
比如,当我希望给我的页面加入 Google 统计,
{
entry: ['./public/src/index.js', './public/src/googleAnalytics.js'],
output: {
path: '/dist',
filename: 'bundle.js'
}
}
当我们这样配置的时候,Webpack 会先打包出 bundle.js
,然后会将 Google 统计的代码插入在 bundle.js
的最后,
entry -- 对象
当我们想要编写一个真正的多页面应用的时候,我们可能会拥有多个 HTML 文件,比如 index.html
或是 profile.html
,我们可以使用对象的方式来配置 Webpack 来告知我们需要生成多个 bundle
文件,
下属例子中,我们将会生成两个 JS 文件,
{
entry: {
'indexEntry': './public/src/index.js',
'profileEntry': './public/src/profile.js'
},
output: {
path: '/dist',
filename: '[name].js' // indexEntry.js and profileEntry.js
}
}
当然我们可以将上述方法组合使用,
{
entry: {
'vendor': ['jquery', 'analytics.js', 'optimizely.js'],
'index': './public/src/index.js',
'profile': './public/src/profile.js'
},
output: {
path: '/dist',
filename: '[name].js' // vendor.js, index.js and profile.js
}
}
output
-- path
Vs publicPath
output
告知 Webpack 在哪里存储输出文件,其中有两个属性会引起混淆,path
和 publicPath
,
path
属性仅仅是告知 Webpack 在哪里存储输出文件,而 publicPath
则是在生产环境编译时给一些插件所引用的静态文件生成 URLs 的公共地址,或是你的静态文件没有存储在本地而是在 CDN 行,
// Development
{
entry: __dirname + '/app/main.js',
output: {
// path: 指明在哪存储 `bundle.js`
path: __dirname + '/public',
// 在开发环境中不要使用 `publicPath` ,除非你的静态资源,比如图片或是 CSS 文件
// 并没有存储在本带,而是在 CDN 上
// publicPath: 'http://mycdn.com/'
filename: 'bundle.js'
}
}
// Production
{
entry: __dirname + '/app/main.js',
output: {
path: __dirname + '/public',
// publicPath: 被众多插件使用,比如 url-loader, file-loader 等,
// 为应用的静态文件生成公共地址,
// 比如:
// .image {
// background-image: url('./test.png');
// }
// 会被编译成,
// .image {
// background-image: url('http://mycdn.com.test.png');
// }
publicPath: 'http://mycdn.com',
filename: 'bundle.js'
}
}
Loaders
和链式调用
Loader 是额外安装的 node
模块,用于将引入的文件编译成为浏览器可使用的文件等,
比如,我们常使用 babel-loader
来转换 ES6 的语法至 ES5,
loaders: [{
test: /\.js$/, // 遍历所有文件,如果后缀名为 `.js` 则使用 loader
exclude: /node_modules/, // 不会遍历 Node_modules 文件夹
loader: 'babel' // 使用 babel-loader
}]
链式调用
我们可以使用链式调用的方式来使用多个 Loader,其语法为使用 !
连接每一个 Loader,链式的执行顺序为 从右至左,
如下述例子,当我们拥有一个名为 "myCssfile.css" ,我们想要读取并将其内容插入进一个 <style>
标签中并直接插入在我们的 HTML 页面中,我们将使用到两个 loader: css-loader
和 style-loader
,
module: {
loaders: [{
test: /\.css$/,
loader: 'style!css'
}]
}
Loaders
自身是可以配置的
通常来讲,我们有两种方式配置 Loader,一种是使用 URL 参数的形式,一种是使用 query
字段,
{
test: /\.png$/,
loader: 'url-loader?limit=1024'
}
{
test: /.\png$/,
loader: 'url-loader',
query: {limit: 1024}
}
插件 (Plugins)
插件同样是额外安装的 node
模块,作用于已经打包好的文件,
比如,UglifyJsPlugin
会压缩混淆打包后的 bundle.js
,
或是 extract-text-webpack-plugin
插件是在其内部调用 css-loader
和 style-loader
来获取所有引用的 CSS 文件并最终打包至一个单独的 style.css
以供引用,
var ETP = require('extract-text-webpack-plugin');
module: {
loaders: [
{
test: /\.css$/,
loader: ETP.extract('style-loader', 'css-loader')
}
]
},
plugins: [
new ExtractTextPlugin('style.css')
]
至此,别眨眼看 Webpack 完结啦,
同时如果文章中有任何错误,欢迎大家指出,好的文章需要你的支持,谢谢
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。