使用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系列(13) This? Yes,this!
Jan 18 Javascript
JQuery的ready函数与JS的onload的区别详解
Nov 21 Javascript
javasctipt如何显示几分钟前、几天前等
Apr 30 Javascript
javascript学习笔记(三)BOM和DOM详解
Sep 30 Javascript
Angularjs制作简单的路由功能demo
Apr 14 Javascript
jQuery实现时尚漂亮的弹出式对话框实例
Aug 07 Javascript
jQuery实现带延迟的二级tab切换下拉列表效果
Sep 01 Javascript
jQuery获取cookie值及删除cookie用法实例
Apr 15 Javascript
用headjs来管理和加载js 提高网站加载速度
Nov 29 Javascript
解决vue 更改计算属性后select选中值不更改的问题
Mar 02 Javascript
seajs和requirejs模块化简单案例分析
Aug 26 Javascript
JS数组push、unshift、pop、shift方法的实现与使用方法示例
Apr 29 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
php中$this->含义分析
2009/11/29 PHP
php学习之数据类型之间的转换代码
2011/05/29 PHP
基于PHP实现数据分页显示功能
2016/05/26 PHP
Yii2中事务的使用实例代码详解
2016/09/07 PHP
php array_values 返回数组的值实例详解
2016/11/17 PHP
详解如何在云服务器上部署Laravel
2017/06/30 PHP
KindEditor在php环境下上传图片功能集成的方法示例
2020/07/20 PHP
CSS中简写属性要注意TRouBLe的顺序问题(避免踩坑)
2021/03/09 HTML / CSS
基于jquery实现拆分姓名的方法(纯JS版)
2013/05/08 Javascript
根据选择不同的下拉值出现相对应的文本输入框
2013/08/01 Javascript
jQuery控制iFrame(实例代码)
2013/11/19 Javascript
JavaScript AOP编程实例
2015/06/16 Javascript
jQuery实现的简单排序功能示例【冒泡排序】
2017/01/13 Javascript
Angularjs单选框相关的示例代码
2017/08/17 Javascript
微信 jssdk 签名错误invalid signature的解决方法
2019/01/14 Javascript
浅谈vue在html中出现{{}}的原因及解决方式
2020/11/16 Javascript
更改Python的pip install 默认安装依赖路径方法详解
2018/10/27 Python
python selenium执行所有测试用例并生成报告的方法
2019/02/13 Python
Python列表删除元素del、pop()和remove()的区别小结
2019/09/11 Python
python实现异常信息堆栈输出到日志文件
2019/12/26 Python
python有几个版本
2020/06/17 Python
实例讲解Python 迭代器与生成器
2020/07/08 Python
python 实现学生信息管理系统的示例
2020/11/28 Python
如何用python批量调整视频声音
2020/12/22 Python
尤妮佳moony海外旗舰店:日本殿堂级纸尿裤品牌
2018/02/23 全球购物
澳洲本土太阳镜品牌:Quay Australia
2019/07/29 全球购物
Diptyque英国官方网站:源自法国的知名香氛品牌
2019/08/28 全球购物
如何将一个描述日期或日期/时间的字符串转换为一个Date对象
2015/10/13 面试题
电气工程及其自动化自我评价四篇
2013/09/24 职场文书
村委会贫困证明
2014/01/14 职场文书
市委常委会班子党的群众路线教育实践活动整改方案
2014/10/25 职场文书
2014年幼儿园教研工作总结
2014/12/04 职场文书
技术员个人工作总结
2015/03/03 职场文书
信访工作个人总结
2015/03/03 职场文书
爱心捐助活动总结
2015/05/09 职场文书
小英雄雨来观后感
2015/06/09 职场文书