Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
yesvods opened this issue Dec 20, 2015 · 20 comments
Open

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

yesvods opened this issue Dec 20, 2015 · 20 comments
Labels

Comments

@yesvods
Copy link
Owner

yesvods commented Dec 20, 2015

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前端开发最基本的用法,更多参数以及功能使用,参考官网

@hollenzhao
Copy link

谢谢分享,学习了。

@CrazyMan2014
Copy link

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

@yesvods
Copy link
Owner Author

yesvods commented Apr 25, 2016

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

@CrazyMan2014
Copy link

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

@yesvods
Copy link
Owner Author

yesvods commented Apr 26, 2016

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

@CrazyMan2014
Copy link

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

@yesvods
Copy link
Owner Author

yesvods commented Apr 26, 2016

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

@CrazyMan2014
Copy link

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

@FrendEr
Copy link

FrendEr commented Apr 26, 2016

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

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

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

var m1 = require('module1');

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

@yesvods
Copy link
Owner Author

yesvods commented Apr 26, 2016

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

@FrendEr
Copy link

FrendEr commented Apr 26, 2016

@yesvods thanks!

@Rookiewan
Copy link

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

@yesvods
Copy link
Owner Author

yesvods commented Feb 14, 2017

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

@Rookiewan
Copy link

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

@yesvods
Copy link
Owner Author

yesvods commented Feb 14, 2017

@Rookiewan js如果是以文本读取,不需要babel-loader。用require('raw!./demo.js'),需要安装一个raw-loader

@Rookiewan
Copy link

@yesvods 感谢回答,里面还有一些 html 和 scss 文件,这样的话是否需要对应的 loader

@yesvods
Copy link
Owner Author

yesvods commented Feb 14, 2017

@Rookiewan loader只是一种转换器,比如你需要文本,raw-loader可以符合你的需求。如果你需要将scss文件转成css,就用scss-loader,后续怎么处理css,还是需要对应的loader.

@Rookiewan
Copy link

@yesvods 好的 明白了,谢谢你,我去试试

@humengchuan123
Copy link

全局安装了,局部引入报错 ,怎么重新处理呢?

@yesvods
Copy link
Owner Author

yesvods commented Mar 28, 2017

@humengchuan123 类库引入是按node_modules目录,一级级往上查找,全局安装的地方未必可以被查找到,一般全局用于可执行命令行,类库引入建议本地安装。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants