Skip to content

前端webpack workflow(二)——Webpack基本使用 #3

Open
@yesvods

Description

@yesvods
Owner

webpack

前言

前一篇文章介绍了webpack以及安装方法,本文将会介绍webpack在单页面应用程序(Single Page Application)与多页面站点不同场合的用法。

输入与输出

跟其他模块加载器类似,webpack也是需要配置一个入口文件,比如是entry.js
有几种配置方式,下面来介绍一下直接把入口文件写在配置文件 webpack.config.js:

module.exports = {
  entry: {
    "entry":"./entry.js"
  },
  output: {
    path: "build"
    filename: "bundle.js"
  }
}

通过命令行

> webpack

很便利地,webpack检测配置文件,读取模块入口与输出路径和文件名,将文件依赖整合成一个文件,输出到build/bundle.js

通过在HTML简单引入

<script src="./build/bundle.js"></script>

就可以在浏览器运行。

加载器

简单的SPA程序加载,包括:JS编译与加载、CSS编译与加载、图片加载与压缩、JS与CSS压缩。

Webpack提供了一套加载器机制,比如:css-loader、style-loader、url-loader等,用于将不同资源加载到js文件中,例如url-loader用于在js中加载png/jpg格式的图片文件,css/style loader 用于加载css文件,less-loader用于将less文件编译成css。

下面介绍一些常用的加载器(详细介绍在这里):

style+css+less加载Bootstrap less版本:

require('style!css!less!./bower_components/bootstrap/bootstrap.less');

style+css 加载一般样式文件:

require('style!css!./styles/main.css');

url 加载图片资源文件:

require('url!./images/logo.png');

json loader加载json格式文件:

require('json!./data.json');

js后缀的文件不需要使用加载器

require('./scripts/main.js');

coffee script加载

require('coffee!./scripts/main.coffee');

喜欢尝鲜的童鞋可以通过Babel loader体验ES6/7特性:

require('babel!./scripts/es6.js');

需要注意的是,避免用babel作为加载器加载所有node_module模块,会出现意外结果,而且大量加载情况下,加载时间很长。babel还可以用作reactjs jsx文件加载使用,详细请看。

配置加载器

刚刚介绍了行内加载资源的方式,如果有很多css或者图片资源需要加载,重复写加载器显得很笨拙,webpack提供另一种方式加载资源。
在配置文件添加配置:

module.exports = {
  module: {
    loaders: [
      {test: /.css$/, loader: "style!css"},
      {test: /.(png|jpg)$/, loader: "url-loader?limit=8192"}
    ]
  }
}

其中test是正则表达式,对符合的文件名使用相应的加载器
/.css$/会匹配 xx.css文件,但是并不适用于xx.sass或者xx.css.zip文件
/.css/除了匹配xx.css也可以匹配xx.css.zip

加载器后可以加入?xx=yy传递参数,表示添加将xx设置为yy(跟http地址Query很像)

需要注意的是,使用加载器前需要使用

> npm i --save xxx-loader

安装相应加载器,并通过--save把依赖配置到package.json中,使用加载器并不需要使用require引入。

搜索路径变量

以上介绍的加载器,可以很方便使用webpack整合日常资源,如果认为webpack仅仅只能做这些,那就让您失望了。

可以看到,以上加载资源时候,都使用相对路径来描述路径,对于那些./app/src/scripts/main.js通过修改webpack配置文件,添加默认搜索路径后,显得更加优雅。

// webpack.config.js
var path = require("path")
module.exports = {
  resolve: {
    alias: {
      js: path.join(__dirname, "./app/src/scripts")
    }
  }
}

更改配置文件后加载:

require("js/main.js");

默认搜索路径配置

对于bower_components死忠们,前端开发少不了几个bower插件,使用gulp可以通过gulp-wiredep来动态把bower.json dependencies加载到指定HTML文件。
在webpack也有非常便利的导入方法:
首先,加入配置

module.exports = {
  resolve: {
    alias: {
      js: path.join(__dirname, "src/scripts"),
      src: path.join(__dirname, "src/scripts"),
      styles: path.join(__dirname, "src/styles"),
      img: path.join(__dirname, "src/img")
    },
    root: [
      path.join(__dirname, "bower_components")
    ]
  },
  plugins: [
    new webpack.ResolverPlugin(
        new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin(".bower.json", ["main"])
      )
  ]
}

resolve.root 表示添加默认搜索路径,使用如下语法:

require("jquery");

webpack会在bower_components/jquery目录下进行查找CommandJS模块node_module/index.js、index.js
但是,因为Bower不属于CommandJS规范范畴,使用的是bower.json main属性指定项目入口文件
说到这里,大家就知道plugins里面那串东东是干嘛的啦

之后,我们就可以很方便在任何js文件里面引用jquery:

var jQuery = $ = require("jquery");

需要注意的是,require的并非jquery.js,而是bower_components目录下的文件夹名

多页面开发

webpack 不仅仅适用于SPA开发,对于多页面站点,webpack支持得很好,通过更改配置文件为多入口:

module.exports = {
  entry: {
    "entry":"./src/scripts/entry.js",
    "swiperEffect":"./src/scripts/swiperEffect.js"
  },
  output: {
    path: "build"
    filename: "[name].bundle.js"
  }
}

output设置里面,[name]代表entry的每一个键值,因此运行webpack时候,会输出对应的两个文件:

build/entry.bundle.js
build/swiperEffect.bundle.js

然后就可以在index.html和about.html两个页面分别引用啦

文件分离

前端工程一项就是减少http请求,这表示需要把多个js合并成一个,但是,单个js文件过大会影响浏览器加载文件速度,由于现在浏览器并发http请求多达6个,可以利用这个特性,将可复用第三方资源库分离加载。

使用CommandJS规范的

//entry.js
require.ensure(["jquery", "imgScroll"], function(require){
  var $ = require("jquery");
  require("imgScroll");
  $("#container").scroll({
    XXX
  })
})

通过require.ensure声明的文件,称作按需加载依赖,这些依赖会独立出来一个文件,待入口模块加载完,需要请求时候才会相继加载

再次编译webpack:

build/entry.bundle.js
build/swiperEffect.bundle.js
build/2.2.bundle.js

其中2.2.bundle.js就是jquery+imgScroll异步加载内容

可以看到2.2.bundle.js在entry.bundle.js加载完后进行异步加载。

webpack 实用命令

除了简单运行webpack,还可以添加几个参数,方便部署文件处理。

输出js文件,经过uglify进行压缩:

> webpack -p

自动监听变化,动态运行webpack编译:

> webpack --watch

通常Dev阶段,使用--watch配合live-server就可以自动化开发繁琐的窗口切换与回车。

以上仅仅介绍了webpack前端开发最基本的用法,更多参数以及功能使用,参考官网

Activity

hollenzhao

hollenzhao commented on Jan 29, 2016

@hollenzhao

谢谢分享,学习了。

CrazyMan2014

CrazyMan2014 commented on Apr 25, 2016

@CrazyMan2014

想问一下,怎么会多一个build/2.2.bundle.js这个文件呢?不是配置输出只有两个文件吗?

yesvods

yesvods commented on Apr 25, 2016

@yesvods
OwnerAuthor

@CrazyMan2014 bundle里面包括需要异步加载的jqueryimgScroll,在执行到require.ensure语句时候才会发起一个请求加载进来。

CrazyMan2014

CrazyMan2014 commented on Apr 26, 2016

@CrazyMan2014

@yesvods 如果我没有配置require.ensure,只是require其他的东西,也会产生1.1.bundle.js文件这些吗?

yesvods

yesvods commented on Apr 26, 2016

@yesvods
OwnerAuthor

@CrazyMan2014 只有通过类似require.ensure才会产生额外的Bundle

CrazyMan2014

CrazyMan2014 commented on Apr 26, 2016

@CrazyMan2014

@yesvods yes我只是require了路由require('./config/routers'),然后它就根据路由产生不同的bundle了

yesvods

yesvods commented on Apr 26, 2016

@yesvods
OwnerAuthor

@CrazyMan2014 可以Share一下项目链接么

CrazyMan2014

CrazyMan2014 commented on Apr 26, 2016

@CrazyMan2014

@yesvods 只是自己弄着玩的,并木有放到github哦

FrendEr

FrendEr commented on Apr 26, 2016

@FrendEr

@yesvods 同时配置了resolve.root 和 resolve.modulesDirectories

resolve: {
  root: __dirname,
  modulesDirectories: ['node_modules']
}

当我在引用一个模块 module1.js 的时候

var m1 = require('module1');

默认的搜索顺序是怎样的?
__dirname/module1 -> node_modules/module1 这样?

yesvods

yesvods commented on Apr 26, 2016

@yesvods
OwnerAuthor

@FrendEr 因为显式声明了root,webpack会优先搜索,搜索顺序就是你描述的那样。

FrendEr

FrendEr commented on Apr 26, 2016

@FrendEr

@yesvods thanks!

Rookiewan

Rookiewan commented on Feb 14, 2017

@Rookiewan

你好,我通过这种方式引进来,为什么报错找不到 module
require('style!css!./styles/main.css');

yesvods

yesvods commented on Feb 14, 2017

@yesvods
OwnerAuthor

@Rookiewan 应该是没有装对应的loader吧,比如style-loader,css-loader

Rookiewan

Rookiewan commented on Feb 14, 2017

@Rookiewan

@yesvods 有装了,因为我想扩展一下 html-webpack-plugin 插件,想要读取本地的一个js 资源文件写到 html里面,但是 require('./demo.js')时,因为用了 es6语法,里面用的 import,会报 import xxx 的错。所以我就用 require('babel-loader!./demo.js') 这样来引入,但是报了 can't found module 的错,babel-loader 是装了的。我也不知道是不是我这样用不行,如果要实现我这种功能。需要怎么做,麻烦你了。

6 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @yesvods@CrazyMan2014@hollenzhao@FrendEr@Rookiewan

        Issue actions

          前端webpack workflow(二)——Webpack基本使用 · Issue #3 · yesvods/Blog