6

上篇文章中简单介绍了webpack的最基本用法,且项目结构十分简单,只有一个html页面、一个css页面、两个js文件。本文将介绍如何使用webpack对具有较为规范的结构的项目进行构建。主要包括以下几个方面:

  1. 进一步了解webpack.config.js

  2. 进一步了解webpack-dev-server

  3. 使webpack支持es6语法

关于webpack.config.js

我们以最常用最简单的项目结构来演示,如下:

myPro
    - css
    - src
    - node-modules
    - dist
    - index.html
    - webpack.config.js
    

这样我们的项目结构就很清晰了。css文件夹中存放样式文件,src文件夹中存放js文件,node-modules中是我们用到的各种包,dist文件存放打包生成的文件。现在我希望做到以下两点

  1. css使用less编写

  2. 打包文件到dist目录下

第一步,在css文件夹中创建以下两个文件
index.less

@import 'demo.less';

demo.less

body {
    background: yellow;

    .main {
        width: 200px;
        height: 200px;
        border: 10px solid red;
    }
}

第二步,在src文件夹中创建文件
content.js

module.exports = 'it works from content.js';

entry.js

require('../css/index.less');
let content = require('./content.js');
alert(content);

第三部,修改index.html如下:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>webpack demo</title>
    </head>
    <body>
        <div class="main" id="main">
            <p>webpack demo</p>
        </div>
    </body>
    <script type="text/javascript" src="./dist/bundle.js"></script>
</html>

至此,我们看到 1、样式文件使用了less编写;2、在index.html页面中js文件路径为./dist/bundle.js

配置less-loader

对于1(样式文件采用less编写),我们需要使用加载器来处理。首先,需要安装less-loader,而less-loader依赖于less,因此需要这样安装

$ npm install less-loader less

然后再config文件中配置对less文件的处理,如下:

module: {
    loaders: [
        {
            test: /\.css$/, 
            loader: "style!css"
        },
        {
            test: /\.less$/,
            loader: "style!css!less"
        }
    ]
}

这里加入了对less文件的处理,需要注意loader的顺序,为style!css!less,意为先使用less加载器处理,解析为普通的css文件,再处理css文件,最后处理样式,类似于pipe的概念。

设置output

在上篇文章中,我们提到了webpack.config.js文件中可以设置output,作为打包的出口参数。如下:

output: {
    path: __dirname,
    filename: "bundle.js"
}

这里设置了两项:pathfilename
其中,path为打包的目录,__dirname指当前目录,filename指文件名。
这里我们希望将文件打包到dist目录下,则可以通过配置path来实现,完整配置如下:

let path = require('path');

module.exports = {
    entry: "./src/entry.js",
    output: {
        path: path.join( __dirname, '/dist'), //这里配置打包路径
        filename: "bundle.js"
    },
    module: {
        loaders: [
            {
                test: /\.css$/, 
                loader: "style!css"
            },
            {
                test: /\.less$/,
                loader: "style!css!less"
            }
        ]
    }
};

至此,我们完成了两步,1、对less文件正确处理; 2、将文件打包到dist目录下。
打包:

$ webpack

用浏览器打开index.html页面,可以看到:

clipboard.png

进一步了解webpack-dev-server

上篇文章提到,webpack-dev-server为我们提供了一个小型的基于node的express服务器,使我们可以通过http://localhost:8080/webpack-dev-server/来访问页面,并且它可以监测文件的变化并在页面中实时显示出来。现在我们再来试下:
启动webpack-dev-server

$ webpack-dev-server

访问http://localhost:8080/webpack-dev-server/
修改content.js文件如下:

module.exports = 'it is another content from content.js';

可以看到,页面自动进行了刷新,但是alert的内容却没有变。这说明监测到了文件的变化,但是我们的index.html加载的js文件并没有变。
那问题出在哪里?

webpack-dev-server原理

webpack-dev-server通过sockjs实现实时变化监测,当文件变化时,服务器就会向客户端发送通知,客户端重新渲染。
每次文件变化都会触发webpack-dev-server对文件进行重新编译,但是这个编译后的文件并不会每次都保存到我们的dist目录下,而是存放在内存中,默认情况下,这个文件的路径为当前路径。也就是说,每次文件变化后,内存中的bundle.js做出了实时的变化,而output中配置的文件其实并没有变。也就是说,如果我们在index.html中使用./bundle.js则能够实现页面内容的实时更新。
那么,如何配置可以使其支持我们当前的写法./dist/bunlde.js呢?就需要用到publicPath这个属性。

outputpublicPath属性

webpack-dev-server默认支持文件路径为当前的路径,可以通过在output中配置publicPath属性对其进行更改,如下:

output: {
    path: path.join( __dirname, '/dist'),
    publicPath: '/dist/',
    filename: "bundle.js"
}

这样设置我们就可以通过./dist/bundle.js路径访问到内存中的文件,在当前路径下已经存在同名文件的情况下,webpack-dev-server会优先使用内存中的文件。

至此,我们已经实现了:

  1. 使用less编写样式文件

  2. 将文件打包到指定目录

  3. 监测文件变化并实时展示

看到,现在我们还是采用的commonJS的规范来实现模块化,而es6为我们提供了exportimport语法来支持模块化,如果想要在项目中使用es6,同样可以通过webpack来配置实现。

webpack支持es6

使webpack支持es6需要用到babel,它可以帮助我们将es6语法转化为es5的格式,可以在这里测试。
首先,需要安装babel

$ npm install babel-loader babel-core

安装babel-preset

$ npm install babel-preset-es2015

然后,配置webpack.config.js,如下:

module: {
  loaders: [
    { test: /\.js$/, exclude: /node_modules/, loader: "babel-loader" }
  ]
}

最后还需要加上babel的配置文件,在项目的根目录下创建文件.babelrc

{ "presets": ["es2015"] }

这样,我们的webpack就支持通过es6exportimport实现模块化了。
修改content.js内容如下:

var content = 'it is the origin content from content.js';

export {content};

修改entry.js内容如下:

require('../css/index.less');

import {content} from './content';

let div = document.getElementById('main');
div.innerHTML = content;

可以看到,我们现在通过es6importexport实现js的模块化,打包:

$ webpack

clipboard.png
打包成功。

结语

本文介绍了如何使用webpack对一个较为系统的项目进行打包,并支持less,es6,同时对webpack-dev-server的原理进行了简要说明。后续还会更深入地学习webpack,希望和大家一同进步。

(本文完)


bupthly
385 声望39 粉丝

竹杖芒鞋轻胜马,一蓑烟雨任平生