webpack

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack相关的知识,希望对你有一定的参考价值。

什么是Webpack?

事实上它是一个打包工具,而不是像RequireJS或SeaJS这样的模块加载器,通过使用Webpack,能够像Node.js一样处理依赖关系,然后解析出模块之间的依赖,将代码打包

安装Webpack

首先得有Node.js

然后通过npm install -g webpack安装webpack,当然也可以通过gulp来处理webpack任务,如果使用gulp的话就npm install --save-dev gulp-webpack

配置Webpack

Webpack的构建过程需要一个配置文件,一个典型的配置文件大概就是这样

var webpack = require(‘webpack‘);
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin(‘common.js‘);

module.exports = {
    entry: {
        entry1: ‘./entry/entry1.js‘,
        entry2: ‘./entry/entry2.js‘
    },
    output: {
        path: __dirname,
        filename: ‘[name].entry.js‘
    },
    resolve: {
        extensions: [‘‘, ‘.js‘, ‘.jsx‘]
    },
    module: {
        loaders: [{
            test: /\.js$/,
            loader: ‘babel-loader‘
        }, {
            test: /\.jsx$/,
            loader: ‘babel-loader!jsx-loader?harmony‘
        }]
    },
    plugins: [commonsPlugin]
};

这里对Webpack的打包行为做了配置,主要分为几个部分:

  • entry:指定打包的入口文件,每有一个键值对,就是一个入口文件
  • output:配置打包结果,path定义了输出的文件夹,filename则定义了打包结果文件的名称,filename里面的[name]会由entry中的键(这里是entry1和entry2)替换
  • resolve:定义了解析模块路径时的配置,常用的就是extensions,可以用来指定模块的后缀,这样在引入模块时就不需要写后缀了,会自动补全
  • module:定义了对模块的处理逻辑,这里可以用loaders定义了一系列的加载器,以及一些正则。当需要加载的文件匹配test的正则时,就会调用后面的loader对文件进行处理,这正是webpack强大的原因。比如这里定义了凡是.js结尾的文件都是用babel-loader做处理,而.jsx结尾的文件会先经过jsx-loader处理,然后经过babel-loader处理。当然这些loader也需要通过npm install安装
  • plugins: 这里定义了需要使用的插件,比如commonsPlugin在打包多个入口文件时会提取出公用的部分,生成common.js

当然Webpack还有很多其他的配置,具体可以参照它的配置文档

执行打包

如果通过npm install -g webpack方式安装webpack的话,可以通过命令行直接执行打包命令,比如这样:

$webpack --config webpack.config.js

这样就会读取当前目录下的webpack.config.js作为配置文件执行打包操作

如果是通过gulp插件gulp-webpack,则可以在gulpfile中写上gulp任务:

var gulp = require(‘gulp‘);
var webpack = require(‘gulp-webpack‘);
var webpackConfig = require(‘./webpack.config‘);
gulp.task("webpack", function() {
    return gulp
        .src(‘./‘)
        .pipe(webpack(webpackConfig))
        .pipe(gulp.dest(‘./build‘));
});

组件编写

使用Babel提升逼格

Webpack使得我们可以使用Node.js的CommonJS规范来编写模块,比如一个简单的Hello world模块,就可以这么处理:

var React = require(‘react‘);

var HelloWorldComponent = React.createClass({
    displayName: ‘HelloWorldComponent‘,
    render: function() {
        return (

<div>Hello world</div>

);
    }
});

module.exports = HelloWorldComponent;

等等,这和之前的写法没啥差别啊,依旧没有逼格...程序员敲码要有geek范,要逼格than逼格,这太low了。现在都ES6了,React的代码也要写ES6,babel-loader就是干这个的。Babel能够将ES6代码转换成ES5。首先需要通过命令npm install --save-dev babel-loader来进行安装,安装完成后就可以使用了,一种使用方式是之前介绍的在webpack.config.js的loaders中配置,另一种是直接在代码中使用,比如:

var HelloWorldComponent = require(‘!babel!jsx!./HelloWorldComponent‘);

那我们应当如何使用Babel提升代码的逼格呢?改造一下之前的HelloWorld代码吧:

import React from ‘react‘;

export default class HelloWorldComponent extends React.Component {
    constructor() {
        super();
        this.state = {};
    }
    render() {
        return (

<div>Hello World</div>

);
    }
}

这样在其他组件中需要引入HelloWorldComponent组件,就只要就可以了:

import HelloWorldComponent from ‘./HelloWorldComponent‘

怎么样是不是更有逼格了?通过import引入模块,还可以直接定义类和类的继承关系,这里也不再需要getInitialState了,直接在构造函数constructor中用this.state = xxx就好了

Babel带来的当然还不止这些,在其帮助下还能尝试很多优秀的ES6特性,比如箭头函数,箭头函数的特点就是内部的this和外部保持一致,从此可以和that_this说再见了

[‘H‘, ‘e‘, ‘l‘, ‘l‘, ‘o‘].map((c) => {
    return (<span>{c}</span>);
});

其他还有很多,具体可以参照Babel的学习文档

样式编写

我是一个强烈地Less依赖患者,脱离了Less直接写CSS就会出现四肢乏力、不想干活、心情烦躁等现象,而且还不喜欢在写Less时候加前缀,平常都是gulp+less+autoprefixer直接处理的,那么在Webpack组织的React组件中要怎么写呢?

没错,依旧是使用loader

可以在webpack.config.js的loaders中增加Less的配置:

{
  test: /\.less$/,
  loader: ‘style-loader!css-loader!autoprefixer-loader!less-loader‘
}

通过这样的配置,就可以直接在模块代码中引入Less样式了:

import React from ‘react‘;

require(‘./HelloWorldComponent.less‘);

export default class HelloWorldComponent extends React.Component {
    constructor() {
        super();
        this.state = {};
    }
    render() {
        return (

<div>Hello World</div>

);
    }
}

其他

Webpack的loader为React组件化提供了很多帮助,像图片也提供了相关的loader:

{ test: /\.png$/, loader: "url-loader?mimetype=image/png" }

更多地loader可以移步webpack的wiki

在Webpack下实时调试React组件

Webpack和React结合的另一个强大的地方就是,在修改了组件源码之后,不刷新页面就能把修改同步到页面上。这里需要用到两个库webpack-dev-serverreact-hot-loader

首先需要安装这两个库,npm install --save-dev webpack-dev-server react-hot-loader

安装完成后,就要开始配置了,首先需要修改entry配置:

entry: {
  helloworld: [
    ‘webpack-dev-server/client?http://localhost:3000‘,
    ‘webpack/hot/only-dev-server‘,
    ‘./helloworld‘
  ]
},

通过这种方式指定资源热启动对应的服务器,然后需要配置react-hot-loader到loaders的配置当中,比如我的所有组件代码全部放在scripts文件夹下:

{
  test: /\.js?$/,
  loaders: [‘react-hot‘, ‘babel‘],
  include: [path.join(__dirname, ‘scripts‘)]
}

最后配置一下plugins,加上热替换的插件和防止报错的插件:

plugins: [
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin()
]

这样配置就完成了,但是现在要调试需要启动一个服务器,而且之前配置里映射到http://localhost:3000,所以就在本地3000端口起个服务器吧,在项目根目录下面建个server.js:

var webpack = require(‘webpack‘);
var WebpackDevServer = require(‘webpack-dev-server‘);
var config = require(‘./webpack.config‘);

new WebpackDevServer(webpack(config), {
  publicPath: config.output.publicPath,
  hot: true,
  historyApiFallback: true
}).listen(3000, ‘localhost‘, function (err, result) {
  if (err) console.log(err);
  console.log(‘Listening at localhost:3000‘);
});

这样就可以在本地3000端口开启调试服务器了,比如我的页面是根目录下地index.html,就可以直接通过http://localhost:3000/index.html访问页面,修改React组件后页面也会被同步修改,这里貌似使用了websocket来同步数据。图是一个简单的效果:

技术分享

以上是关于webpack的主要内容,如果未能解决你的问题,请参考以下文章

Vue报错:Uncaught TypeError: Cannot assign to read only property 'exports' of object 的解决方法(代码片段

如何使用webpack加载库源映射?

浅析 -- webpack

报错:✘ http://eslint.org/docs/rules/indent Expected indentation of 0 s paces but found 2(代码片段

报错:✘ http://eslint.org/docs/rules/indent Expected indentation of 0 s paces but found 2(代码片段

无法创建中继容器; graphql.js 文件似乎有 webpack 工件?