使用webpack构建应用的方法步骤


Posted in Javascript onMarch 04, 2019

如何使用webpack

npm init -y
npm install webapck webpack-cli --save-dev
touch webpack.config.js

在webpack.config.js中下面添加内容

const path = require('path');

module.exports = {
 entry: './src/index.js',
 output: {
  filename: 'main.js',
  path: path.resolve(__dirname, 'dist')
 }
};
  • entry:工程资源的入口,可以是单个文件,也可以是多个文件,通过每一个资源入口,webpack会一次去寻找它的依赖进行模块打包。我们可以把entry理解为整个依赖树的根,每个入口都将对应一个最终生成的打包结果。
  • output:这是一个配置对象,通过它我们可以对最终打包的产物进行配置,这里配置了两个属性,:
    • path:打包资源放置的路劲,必须为绝对路径。
    • filename:打包结果的文件名。

定义好配置文件后,用npx webpack或者./node_modules/.bin/webpack执行

使用loader

项目中需要引入一个css文件,如果直接用webpack去执行就会报错,需要再webpack中加入loader机制

module.exports = {
  ...
  module: {
    rules: [
      {
        // 用正则去匹配 .css 结尾的文件,然后需要使用 loader 进行转换
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      }
    ]
  }
}

编译之前还需要安装style-loader和css-loader

npm install --save-dev style-loader css-laoder

注意:

use属性的值是一个使用loader名称组成的数组,loader执行的顺序是从后往前的,由于loader执行有顺序,故不能写成这样

use: ['css-loader', 'style-loader']

每个loader都可以通过URL queryString的方式传入参数,比如'css-loader?url'

style-loader的原理:是将css的内容使用javascript的字符串存储起来,在网页执行javascript时通过DOM操作,动态地向HTML head标签里插入HTML style标签。

配置loader的方式也可以用Object来实现

use: ['style-loader', {
  loader: 'css-loader',
  options: {
    url: true
  }
}]

使用plugin

loader的作用是被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,插件的范围包括,从打包优化和压缩,一直到重新定义环节中的变量。

如果想要使用一个插件,我们只需要require()它,然后把它添加到plugins数组中。我们可以在一个配置文件中因为不同的目的多次使用用一个插件,因此我们可以使用new操作符来创建它的实列。

上面使用loader把css加载到js中去,现在使用extract-text-webpack-plugin插件把bundle.js文件里的css提取到单独的文件中

// 提取 css 的插件
const ExtractTextPlugin = require('extract-text-webpack-plugin')

module: {
  rules: [
    {
      // 用正则去匹配 .css 结尾的文件,然后需要使用 loader 进行转换
      test: /\.css$/,
      loaders: ExtractTextPlugin.extract({
        //转换 .css需要使用的 loader
        use: ['css-loader']
      })
    }
  ]
},
plugins: [
  //从 js 文件中提取出来的 .css 文件名称
  new ExtractTextPlugin({
    filename: 'main.css'
  })
]

编译之前需要安装extract-text-webpack-plugin

npm install --save-dev extract-text-webpack-plugin

执行webpack时报错需要这样安装

npm install extract-text-webpack-plugin@next

DevServer

官方网站

安装

npm install webpack-dev-server --save-dev

然后进行简单的配置

devServer:{
  port: 3000,
  publicPath: "/dist"
}

然后用./node_modules/.bin/webpack-dev-server执行

资源压缩

npm i uglifyJSPlugin-webpack-plugin --save-dev

配置文件

const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
plugins: [
  new UglifyJSPlugin({
    //默认是 false 需要手动开启
    parallel: true
  })
]

或者

optimization: {
  minimizer: [new UglifyJsPlugin()],
},

按需加载

在代码层面,webpack支持两种方式进行异步模块加载,一种是CommonJS形式的require.ensure,一种是ES6 Module形式的异步import()

异步加载的脚本不允许使用document.write,所以将module.js的代码改成console.log

export const log = function(){
  console.log('module.js loaded.')
}

编辑app.js,将module.js以异步的形式加载进来

import('./module.js').then(module =>{
  module.log()
}).catch(error => "An error occurred while loading the module")
document.write('app.js loaded.')

修改配置

module.exports = {
  mode: "production",
  entry: './app.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: "./dist"
  },
}

这里我们在output中添加了一个配置项publicPath,它是webpack中一个很重要有很容易引起迷惑的配置,当我们的工程中有按需加载以及图片和文件等外部资源时,就需要它来配置这些资源的路径,否则页面上就会报404,这里我们将publicPath配置为相对于html的路径,使按需加载的资源生产在dist目录下,并且能正确地引用到它。

重新打包之后你会发现打包结果中多出一个1.mian.js,这里面就是将来会被异步加载进来的内容。刷新页面并查看chrome的network标签,可以看到页面会请求1.main.js。它并不来源于index.html中的引用,而是通过main.js在页面插入了script标签来将其引入的。

使用webpack的构建特性

从2.0.0版本开始,webpack开始加入了更多的可以优化构建过程的特性。

tree-shaking

在关于模块的那一篇文章中我们提到过,ES6 Module的模块依赖解析是在代码静态分析过程中进行的。换句话说,它可以在代码的编译过程中得到依赖树,而非运行时。利用这一点webpack提供tree-shaking功能,它可以帮助我们检测工程中哪些模块有从未被引用到的代码,这些代码不可能被执行到,因此也称为“死代码”。通过tree-shaking,webpack可以在打包过程中去掉这些死代码来减小最终的资源体积。

开启tree-shaking特性很简单,只要保证模块遵循ES6 Module的形式定义即可,这意味着之前所有我们的例子其实都是默认已经开启了的。但是要注意如果在配置中使用了babel-preset-es2015或者babel-preset-env,则需要将其模块依赖解析的特性关掉,如:

presets: [
  [env, {module: false}]
]

这里我们测试一下tree-shaking的功能,编辑module.js:

// module.js 
export const log = function() { 
  console.log('module.js loaded.'); 
} 

export const unusedFunc = function() { 
  console.log('not used'); 
}

打开页面查看1.main.js的内容,应该可以发现unusedFunc的代码是不存在的,因为它没有被别的模块使用,属于死代码,在tree-shaking的过程中被优化掉了。

tree-shaking最终的效果依赖于实际工程的代码本身,在我对于实际工程的测试中,一般可以将最终的体积减小3%~5%。总体来看,我认为如果要使tree-shaking发挥真正的效果还要等几年的时间,因为现在大多数的npm模块还是在使用CommonJS,因此享受不了这个特性带来的优势。

scope-hoisting

scope-hoisting(作用域提升)是由webpack3提供的特性。在大型的工程中模块引用的层级往往较深,这会产生比较长的引用链。scope-hoisting可以将这种纵深的引用链拍平,使得模块本身和其引用的其它模块作用域处于同级。这样的话可以去掉一部分 webpack的附加代码,减小资源体积,同时可以提升代码的执行效率。

目前如果要开启scope-hoisting,需要引入它的一个内部插件:

module.exports = { 
  plugins: [ 
    new webpack.optimize.ModuleConcatenationPlugin() 
  ] 
}

scope-hoisting生效后会在bundle.js中看到类似下面的内容,你会发现log 的定义和调用是在同一个作用域下了:

// CONCATENATED MODULE: ./module.js 
const log = function() { 
  console.log('module.js loaded.'); 
} 

// CONCATENATED MODULE: ./app.js 
log();

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用 Javascript 验证表单(form)中多选框(checkbox)值
Sep 08 Javascript
使用jquery与图片美化checkbox和radio控件的代码(打包下载)
Nov 11 Javascript
jQuery中调用WebService方法小结
Mar 28 Javascript
在JavaScript里嵌入大量字符串常量的实现方法
Jul 07 Javascript
使用jQuery jqPlot插件绘制柱状图
Dec 18 Javascript
JavaScript实现跑马灯抽奖活动实例代码解析与优化(一)
Feb 16 Javascript
Bootstrap基本样式学习笔记之标签(5)
Dec 07 Javascript
jQuery实现获取隐藏div高度的方法示例
Feb 09 Javascript
通过button将form表单的数据提交到action层的实例
Sep 08 Javascript
vue2.0 实现导航守卫(路由守卫)
May 21 Javascript
从组件封装看Vue的作用域插槽的实现
Feb 12 Javascript
JavaScript如何把两个数组对象合并过程解析
Oct 10 Javascript
详解element-ui中form验证杂记
Mar 04 #Javascript
JS使用数组实现的队列功能示例
Mar 04 #Javascript
JS使用栈判断给定字符串是否是回文算法示例
Mar 04 #Javascript
微信小程序textarea层级过高(盖住其他元素)问题的解决办法
Mar 04 #Javascript
一步快速解决微信小程序中textarea层级太高遮挡其他组件
Mar 04 #Javascript
使用ESLint禁止项目导入特定模块的方法步骤
Mar 04 #Javascript
微信小程序textarea层级过高的解决方法
Mar 04 #Javascript
You might like
冰滴咖啡制作步骤
2021/03/03 冲泡冲煮
phpmyadmin操作流程
2006/10/09 PHP
自定义PHP分页函数
2006/10/09 PHP
解决控件遮挡问题:关于有窗口元素和无窗口元素
2007/01/28 PHP
PHP防止跨域提交表单
2013/11/01 PHP
php猜单词游戏
2015/09/29 PHP
PHP构造二叉树算法示例
2017/06/21 PHP
PHP格式化显示时间date()函数代码
2018/10/03 PHP
锋利的jQuery 要点归纳(三) jQuery中的事件和动画(上:事件篇)
2010/03/24 Javascript
jQuery 无刷新分页实例代码
2013/11/12 Javascript
JavaScript的strict模式与with关键字介绍
2014/02/08 Javascript
JavaScript DOM操作表格及样式
2015/04/13 Javascript
Backbone.js的Hello World程序实例
2015/06/19 Javascript
基于JavaScript实现Json数据根据某个字段进行排序
2015/11/24 Javascript
js实现手机web图片左右滑动效果
2017/12/29 Javascript
详解javascript中的Error对象
2019/04/25 Javascript
微信小程序中插入激励视频广告并获取收益(实例代码)
2019/12/06 Javascript
jQuery操作事件完整实例分析
2020/01/10 jQuery
Vue父子传递实例讲解
2020/02/14 Javascript
JavaScript onclick事件使用方法详解
2020/05/15 Javascript
[02:04]2014DOTA2国际邀请赛 BBC小组赛第三天总结
2014/07/12 DOTA
[40:06]DOTA2亚洲邀请赛 4.3 突围赛 Liquid vs VGJ.T 第一场
2018/04/04 DOTA
python list转dict示例分享
2014/01/28 Python
Python使用Supervisor来管理进程的方法
2015/05/28 Python
Python读取Excel表格,并同时画折线图和柱状图的方法
2018/10/14 Python
Python3 jupyter notebook 服务器搭建过程
2018/11/30 Python
详解python tkinter包获取本地绝对路径(以获取图片并展示)
2020/09/04 Python
python 实现图片批量压缩的示例
2020/12/18 Python
优秀教师主要事迹
2014/02/01 职场文书
加多宝凉茶广告词
2014/03/18 职场文书
优秀毕业生求职信
2014/06/05 职场文书
小学安全汇报材料
2014/08/14 职场文书
退休欢送会主持词
2015/07/01 职场文书
酒吧七夕情人节宣传语
2015/11/24 职场文书
2019入党申请书格式
2019/06/25 职场文书
SQL优化老出错,那是你没弄明白MySQL解释计划用法
2021/11/27 MySQL