苦逼前端

webpack-dev-server编译文件写入磁盘

Javascript2018-04-12 18:41

了解webpack-dev-server的同学们都知道,启用它之后编译生成的文件是存在内存里不落磁盘的,但如果我就是想落磁盘应该怎么操作呢?

先来看看webpack官方是怎么回复这个问题的:#issue62,先是让用webpack --watch来解决,然后质疑了为什么会有这种需求,再然后另外一位Contributor回答说假如你监听的端口是9000,那么可以访问http://localhost:9000/webpack-dev-server来查看生成的文件。

这些回答都没有实际解决我们的问题:我们要在磁盘上查看,要用自己的编辑器打开甚至debugger,而不是在浏览器的资源管理器里。然后又有同学提出了使用类似write-file-webpack-plugin的插件来实现写入磁盘,stackoverflow上的高票回答是这样:
webpack --watch & webpack-dev-server --inline --progress --colors,虽然这些方法实现了文件写入磁盘,但我们访问的devServer仍然是使用了内存中的文件,也就是说,我们去磁盘上修改编译后这些文件是不会生效的。那有什么方法能够实现,既让文件落磁盘,又能让devServer使用落在磁盘上的文件呢?

既然官方没打算做这方面的支持,我们只能自己想办法了,想到webpack-dev-serversetup,原本它是用于mock数据的神器,既然能模拟数据,那肯定也能接收到文件请求吧,我们的思路就是监听文件请求然后读取编译目录中对应的文件来响应。由于我习惯于使用webpackNode API,所以编译文件落磁盘就一起写了,这个过程也并不复杂,只需要在webpack的emit阶段拿到编译结果,从编译结果中拿到编译文件然后写入磁盘就可以了。示例代码:

import fs from 'fs';
import url from 'url';
import path from 'path';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';

const releaseDir = './target';
const config = {
    entry: {
        main: ['./index.js']
    },
    output: {
        filename: '[name].js',
        chunkFilename: '[name].js',
        path: path.join(__dirname, releaseDir),
        publicPath: releaseDir
    },
    module: {
        rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            use: [{ loader: 'babel-loader' }]
        }]
    }
};
const compiler = webpack(config);
//文件落磁盘
compiler.plugin('emit', (compilation, callback) => {
    const assets = compilation.assets;
    let file, data;
    Object.keys(assets).forEach(key => {
        file = path.resolve(__dirname, releaseDir, key);
        data = assets[key].source();
        fs.writeFileSync(file, data);
    });
    callback();
});
const server = new WebpackDevServer(compiler, {
    contentBase: path.join(__dirname, releaseDir),
    stats: { colors: true },
    setup: app => {
        //监听文件请求,并查找对应文件进行响应
        app.get('*.*', (req, res) => {
            const urlJson = url.parse(req.url, true);
            const pathname = urlJson['pathname'];
            const filePath = path.join(releaseDir, pathname);
            fs.readFile(filePath, (err, fileData) => {
                res.end(fileData);
            });
        });
    }
});

server.listen(3000);

完整的例子在这里

需要注意的是,setupwebpack-dev-server@3.0.0及以后将要被移除,取而代之的是beforeafter,用法是一致的。

相关库的版本:
webpack: 2.7.0
webpack-dev-server: 2.11.2

评论(3)
  • 180.168.253.*: 挽~1年1个月前
  • 219.142.22.*: 28行报错,API变了,求作者更新1年1个月前
  • 58.209.180.*: 19个月前
还可输入200个字