GVKun编程网logo

详解webpack+express多页站点开发(webpack多页应用)

10

想了解详解webpack+express多页站点开发的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于webpack多页应用的相关问题,此外,我们还将为您介绍关于express_webpack

想了解详解webpack+express多页站点开发的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于webpack多页应用的相关问题,此外,我们还将为您介绍关于express_webpack自动刷新、express制作小型热加载打包webpack--react篇、Express启动webpack打好的包、Express搭建在线便利贴——Webpack配置的新知识。

本文目录一览:

详解webpack+express多页站点开发(webpack多页应用)

详解webpack+express多页站点开发(webpack多页应用)

学习了webpack门级的教程后,觉得可能是专门为单页应用而量身打造的,比如webpack+react、webpack+vue等,都可以解决各种资源的依赖加载、打包的问题。甚至css都是打包在js里去动态添加到dom文档中的。

那如果我们想要想要多页的普通的web站点,css独立出来,js加载需要模块?

项目地址:

初始化项目、安装依赖

package.json

rush:js;"> "devDependencies": { "css-loader": "^0.23.1","extract-text-webpack-plugin": "^1.0.1","file-loader": "^0.8.5","html-loader": "^0.4.3","html-webpack-plugin": "^2.9.0","jquery": "^1.12.0","less": "^2.6.0","less-loader": "^2.2.2","sass-loader": "^4.0.2","style-loader": "^0.13.0","url-loader": "^0.5.7","webpack": "^1.12.13","webpack-dev-server": "^1.14.1" }

目录结构(我用的express框架,其他的根据个人需求)

rush:plain;"> - webpackDemo - src #代码开发目录 - css #css目录,按照页面(模块)、通用、第三方三个级别进行组织 + page + common + lib - js #JS脚本,按照page、components进行组织 + page + components + template #HTML模板 - node_modules #所使用的nodejs模块 - public #express静态资源文件 - dist #webpack编译打包输出目录,无需建立目录可由webpack根据配置自动生成 + css + js + img #图片资源 + view #express静态资源文件(webpack编译打包输出view目录) package.json #项目配置 webpack.config.js #webpack配置

开发页面

在src/js/page目录下建立index.js文件,在src/view目录下建立index.html文件。入口js和模板文件名对应。

index.html 内容如下:

rush:xhtml;"> <Meta charset="UTF-8"> <a href="https://www.jb51.cc/tag/shouye/" target="_blank">首页</a>

就是这样一个简单的HTML模板,不要引入任何CSS和JS,通过webpack打包就可以自动帮我们引入。

index.js内容如下:

rush:js;"> //引入css require("../../css/lib/base.css"); require("../../css/page/index.scss"); $('body').append('');

page1.html:

rush:xhtml;"> <Meta charset="UTF-8"> page1

page1.js:

rush:js;"> //引入css require("../../css/lib/base.css"); require("../../css/page/page1.less"); $('body').html('page1');

webpack配置(我用的express框架,其他的根据个人需求)

rush:js;"> var path = require('path'); var webpack = require('webpack'); /* extract-text-webpack-plugin插件, 有了它就可以将你的样式提取到单独的css文件里, 妈妈再也不用担心样式会被打包到js文件里了。 */ var ExtractTextPlugin = require('extract-text-webpack-plugin'); /* html-webpack-plugin插件,重中之重,webpack中生成HTML的插件, 具体可以去这里查看https://www.npmjs.com/package/html-webpack-plugin */ var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: { //配置入口文件,有几个写几个
index: './src/js/page/index.js',page1: './src/js/page/page1.js'
},output: {
path: path.join(__dirname,'./public/dist/'),//输出目录的配置,模板、样式、脚本、图片等资源的路径配置都相对于它
publicPath: '/dist/',//模板、样式、脚本、图片等资源对应的server上的路径
filename: 'js/[name].js',//每个页面对应的主js的生成配置
chunkFilename: 'js/[id].chunk.js' //chunk生成的配置
},module: {
loaders: [ //加载器,关于各个加载器的参数配置,可自行搜索之。
{
test: /.css$/,//配置css的抽取器、加载器。'-loader'可以省去
loader: ExtractTextPlugin.extract('style-loader','css-loader')
},{
test: /.less$/,//配置less的抽取器、加载器。中间!有必要解释一下,
//根据从右到左的顺序依次调用less、css加载器,前一个的输出是后一个的输入
//你也可以开发自己的loader哟。有关loader的写法可自行谷歌之。
loader: ExtractTextPlugin.extract('css!less')
},{
test: /.scss$/,//配置scss的抽取器、加载器。中间!有必要解释一下,
//根据从右到左的顺序依次调用scss、css加载器,前一个的输出是后一个的输入
//你也可以开发自己的loader哟。有关loader的写法可自行谷歌之。
loader: ExtractTextPlugin.extract('css!scss')
},{
//html模板加载器,可以处理引用的静态资源,默认配置参数attrs=img:src,处理图片的src引用的资源
//比如你配置,attrs=img:src img:data-src就可以一并处理data-src引用的资源了,就像下面这样
test: /.html$/,loader: "html?attrs=img:src img:data-src"
},{
//文件加载器,处理文件静态资源
test: /.(woff|woff2|ttf|eot|svg)(\?v=[0-9].[0-9].[0-9])?$/,loader: 'file-loader?name=./fonts/[name].[ext]'
},{
//图片加载器,雷同file-loader,更适合图片,可以将较小的图片转成base64,减少http请求
//如下配置,将小于8192byte的图片转成base64码
test: /.(png|jpg|gif)$/,loader: 'url-loader?limit=8192&name=./img/[hash].[ext]'
}
]
},plugins: [
new webpack.ProvidePlugin({ //加载jq
$: 'jquery'
}),new webpack.optimize.CommonsChunkPlugin({
name: 'commons',// 将公共模块提取,生成名为commons的chunk
chunks: ['index','page1'],//提取哪些模块共有的部分
minChunks: 2 // 提取至少2个模块共有的部分
}),new ExtractTextPlugin('css/[name].css'),//单独使用link标签加载css并设置路径,相对于output配置中的publickPath

//HtmlWebpackPlugin,模板<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>相关的配置,每个对于<a href="https://www.jb51.cc/tag/yige/" target="_blank">一个</a><a href="https://www.jb51.cc/tag/yemian/" target="_blank">页面</a>的配置,有几个写几个
new HtmlWebpackPlugin({ //根据模板插入css/js等<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>最终HTML
  favicon: './src/favicon.ico',//favicon路径,通过webpack引入同时可以<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>hash值
  filename: '../../views/index.html',//<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>的html存放路径,相对于path
  template: './src/template/index.html',//html模板路径
  inject: 'body',//js插入的位置,true/'head'/'body'/false
  hash: true,//为静态资源<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>hash值
  chunks: ['commons','index'],//需要引入的chunk,不配置就会引入所有<a href="https://www.jb51.cc/tag/yemian/" target="_blank">页面</a>的资源
  minify: { //压缩HTML<a href="https://www.jb51.cc/tag/wenjian/" target="_blank">文件</a>  
    removeComments: true,//移除HTML中的注释
    collapseWhitespace: false //<a href="https://www.jb51.cc/tag/shanchu/" target="_blank">删除</a>空白符与换行符
  }
}),new HtmlWebpackPlugin({ //根据模板插入css/js等<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>最终HTML
  favicon: './src/favicon.ico',//favicon路径,通过webpack引入同时可以<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>hash值
  filename: '../../views/page1.html',//<a href="https://www.jb51.cc/tag/shengcheng/" target="_blank">生成</a>的html存放路径,相对于path
  template: './src/template/page1.html',//html模板路径
  inject: true,'list'],//移除HTML中的注释
    collapseWhitespace: false //<a href="https://www.jb51.cc/tag/shanchu/" target="_blank">删除</a>空白符与换行符
  }
})

// new webpack.HotModuleReplacementPlugin() //热加载

],//使用webpack-dev-server,提高开发效率
// devServer: {
// contentBase: './',// host: 'localhost',// port: 9090,//默认8080
// inline: true,//可以监控js变化
// hot: true,//热启动
// }
};

好了,完成以上的这些配置之后,执行webpack打包命令完成项目打包。

rush:plain;"> Hash: e6219853995506fd132a Version: webpack 1.14.0 Time: 1338ms Asset Size Chunks Chunk Names js/index.js 457 bytes 0 [emitted] index js/page1.js 392 bytes 1 [emitted] page1 js/commons.js 306 kB 2 [emitted] commons css/index.css 62 bytes 0 [emitted] index css/page1.css 62 bytes 1 [emitted] page1 css/commons.css 803 bytes 2 [emitted] commons favicon.ico 1.15 kB [emitted] ../../view/index.html 496 bytes [emitted] ../../view/page1.html 499 bytes [emitted] [0] ./src/js/page/index.js 170 bytes {0} [built] [0] ./src/js/page/page1.js 106 bytes {1} [built] + 7 hidden modules Child html-webpack-plugin for "../../view/page1.html": + 1 hidden modules Child html-webpack-plugin for "../../view/index.html": + 1 hidden modules Child extract-text-webpack-plugin: + 2 hidden modules Child extract-text-webpack-plugin: + 2 hidden modules Child extract-text-webpack-plugin: + 2 hidden modules

此时,前往views目录下查看生成的index.html文件,如下:

rush:xhtml;"> <Meta charset="UTF-8"> <a href="https://www.jb51.cc/tag/shouye/" target="_blank">首页</a> nofollow" rel="stylesheet">nofollow" rel="stylesheet">

可以看到生成的文件除了保留原模板中的内容以外,还根据入口文件index.js的定义,自动添加需要引入CSS与JS文件,以及favicon,同时还添加了相应的hash值。

两个问题

  1. webpack如何自动发现entry文件及进行相应的模板配置
  2. 如何直接处理样式、脚本自动引入问题
rush:js;"> var path = require('path'); var webpack = require('webpack'); var glob = require('glob'); /* extract-text-webpack-plugin插件, 有了它就可以将你的样式提取到单独的css文件里, 妈妈再也不用担心样式会被打包到js文件里了。 */ var ExtractTextPlugin = require('extract-text-webpack-plugin'); /* html-webpack-plugin插件,重中之重,webpack中生成HTML的插件, 具体可以去这里查看https://www.npmjs.com/package/html-webpack-plugin */ var HtmlWebpackPlugin = require('html-webpack-plugin'); /** *将公共模块提取,生成名为`commons`的chunk */ var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; //压缩 var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin;

//判断开发模式
var debug = process.env.NODE_ENV !== 'production';
var getEntry = function(globPath,pathDir) {
var files = glob.sync(globPath);
var entries = {},entry,dirname,basename,pathname,extname;
for (var i = 0; i < files.length; i++) {
entry = files[i];
dirname = path.dirname(entry); //文件目录
extname = path.extname(entry); //后缀名
basename = path.basename(entry,extname); //文件名
pathname = path.join(dirname,basename);
pathname = pathDir ? pathname.replace(new RegExp('^' + pathDir),'') : pathname;
entries[pathname] = ['./' + entry]; //这是在osx系统下这样写 win7 entries[basename]
}
console.log(entries);
return entries;
}

//入口(通过getEntry方法得到所有的页面入口文件)
var entries = getEntry('src/js/page/*/.js','src/js/page/');
//提取哪些模块共有的部分从entries里面获得文件名称
var chunks = Object.keys(entries);
//模板页面(通过getEntry方法得到所有的模板页面)
var pages = Object.keys(getEntry('src/template/*/.html','src/template/'));

console.log(pages)

var config = {
entry: entries,output: {
path: path.join(__dirname,//每个页面对应的主js的生成配置
chunkFilename: 'js/[id].chunk.js?[chunkhash]' //chunk生成的配置
},module: {
loaders: [ //加载器
{
test: /.css$/,loader: ExtractTextPlugin.extract('style','css')
},loader: ExtractTextPlugin.extract('css!less')
},{
test: /.html$/,loader: "html?-minimize" //避免压缩html,https://github.com/webpack/html-loader/issues/50
},{
test: /.(woff|woff2|ttf|eot|svg)(\?v=[0-9].[0-9].[0-9])?$/,loader: 'file-loader?name=fonts/[name].[ext]'
},{
test: /.(png|jpe?g|gif)$/,loader: 'url-loader?limit=8192&name=imgs/[name]-[hash].[ext]'
}
]
},new CommonsChunkPlugin({
name: 'commons',// 将公共模块提取,生成名为commons的chunk
chunks: chunks,minChunks: chunks.length // 提取所有entry共同依赖的模块
}),//单独使用link标签加载css并设置路径,相对于output配置中的publickPath
debug ? function() {} : new UglifyJsPlugin({ //压缩代码
compress: {
warnings: false
},except: ['$super','$','exports','require'] //排除关键字
}),]
};

pages.forEach(function(pathname) {
var conf = {
filename: '../../views/' + pathname + '.html',//生成的html存放路径,相对于path
template: 'src/template/' + pathname + '.html',//html模板路径
inject: false,//js插入的位置,true/'head'/'body'/false
/*

  • 压缩这块,调用了html-minify,会导致压缩时候的很多html语法检查问题,
  • 如在html标签属性上使用{{...}}表达式,所以很多情况下并不需要在此配置压缩项,
  • 另外,UglifyJsPlugin会在压缩代码的时候连同html一起压缩。
  • 为避免压缩html,需要在html-loader上配置'html?-minimize',见loaders中html-loader的配置。
    */
    // minify: { //压缩HTML文件
    // removeComments: true,//移除HTML中的注释
    // collapseWhitespace: false //删除空白符与换行符
    // }
    };
    if (pathname in config.entry) {
    favicon: './src/favicon.ico',//favicon路径,通过webpack引入同时可以生成hash值
    conf.inject = 'body';
    conf.chunks = ['commons',pathname];
    conf.hash = true;
    }
    config.plugins.push(new HtmlWebpackPlugin(conf));
    });
    module.exports = config;

下面的代码和上面的差不多,本质上的区别就是把通过一个方法把所有的相关的文件放到一个对象里这样就完成了自动引入的效果了!

以上均为在mac osx 系统的配置,win7路径可能会有不同

glob: 这边解析出来的不一样:

但要求最终

rush:plain;"> entries: { index: [ './src/template/index.js' ],page1: [ './src/template/page1.js' ] }

pages:
[ 'index','page1' ]

要以根据个人电脑的配置相应的更改

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小编。

express_webpack自动刷新

express_webpack自动刷新

现在,webpack可以说是最流行的模块加载器(module bundler)。一方面,它为前端静态资源的组织和管理提供了相对较完善的解决方案,另一方面,它也很大程度上改变了前端开发的工作流程。在应用了webpack的开发流程中,想要继续“自动刷新”的爽快体验,就可能得额外做一些事情。

webpack与自动刷新

本文并不打算介绍webpack,如果你还不清楚它是什么,推荐阅读下面几篇入门文章:

  • Beginner’s guide to Webpack

  • Developing with Webpack

  • webpack-howto

webpack要求静态资源在被真正拿来访问之前,都要先完成一次编译,即运行完成一次webpack命令。因此,自动刷新需要调整到适当的时间点。也就是说,修改了css等源码并保存后,应该先触发一次webpack编译,在编译完成后,再通知浏览器去刷新。

开发Express项目的问题

现在有这样的一个应用了webpack的Express项目,目录结构如下:

Express应用的目录结构

其中,client内是前端的静态资源文件,比如css、图片以及浏览器内使用的javascript。server内是后端的文件,比如express的routes、views以及其他用node执行的javascript。根目录的app.js,就是启动express的入口文件了。

开发的时候我们会怎样做呢?

先启动Express服务器,然后在浏览器中打开某个页面,接下来再编辑源文件。那么,问题就来了,比如我编辑.scss源文件,即使我只改了一小点,我也得在命令行里输入webpack等它编译完,然后再切到浏览器里按一下F5,才能看到修改后的效果。

再比如,我修改了routes里的.js文件想看看结果,我需要到命令行里重启一次Express服务器,然后同样切到浏览器里按一下F5。

这可真是太费事了。

所以,我们要让开发过程愉快起来。

改进目标

我们希望的Express&Webpack项目的开发过程是:

  • 如果修改的是client里的css文件(包括.scss等),保存后,浏览器不会整页刷新,新的样式效果直接更新到页面内。

  • 如果修改的是client里的javascript文件,保存后,浏览器会自动整页刷新,得到更新后的效果。

  • 如果修改的是server里的文件,保存后,服务器将自动重启,浏览器会在服务器重启完毕后自动刷新。

经过多次尝试,我最终得到了一个实现了以上这些目标的项目配置。接下来,本文将说明这个配置是如何做出来的。

从webpack-dev-server开始

首先,webpack已经想到了开发流程中的自动刷新,这就是webpack-dev-server。它是一个静态资源服务器,只用于开发环境。

一般来说,对于纯前端的项目(全部由静态html文件组成),简单地在项目根目录运行webpack-dev-server,然后打开html,修改任意关联的源文件并保存,webpack编译就会运行,并在运行完成后通知浏览器刷新。

和直接在命令行里运行webpack不同的是,webpack-dev-server会把编译后的静态文件全部保存在内存里,而不会写入到文件目录内。这样,少了那个每次都在变的webpack输出目录,会不会觉得更清爽呢?

如果在请求某个静态资源的时候,webpack编译还没有运行完毕,webpack-dev-server不会让这个请求失败,而是会一直阻塞它,直到webpack编译完毕。这个对应的效果是,如果你在不恰当的时候刷新了页面,不会看到错误,而是会在等待一段时间后重新看到正常的页面,就好像“网速很慢”。

webpack-dev-server的功能看上去就是我们需要的,但如何把它加入到包含后端服务器的Express项目里呢?

webpack-dev-middleware和webpack-hot-middleware

Express本质是一系列middleware的集合,因此,适合Express的webpack开发工具是webpack-dev-middleware和webpack-hot-middleware。

webpack-dev-middleware是一个处理静态资源的middleware。前面说的webpack-dev-server,实际上是一个小型Express服务器,它也是用webpack-dev-middleware来处理webpack编译后的输出。

webpack-hot-middleware是一个结合webpack-dev-middleware使用的middleware,它可以实现浏览器的无刷新更新(hot reload)。这也是webpack文档里常说的HMR(Hot Module Replacement)。

参考webpack-hot-middleware的文档和示例,我们把这2个middleware添加到Express中。

webpack配置文件部分

首先,修改webpack的配置文件(为了方便查看,这里贴出了webpack.config.js的全部代码):

var webpack = require(''webpack'');
var path = require(''path''); var publicPath = ''http://localhost:3000/''; var hotMiddlewareScript = ''webpack-hot-middleware/client?reload=true''; var devConfig = { entry: { page1: [''./client/page1'', hotMiddlewareScript], page2: [''./client/page2'', hotMiddlewareScript] }, output: { filename: ''./[name]/bundle.js'', path: path.resolve(''./public''), publicPath: publicPath }, devtool: ''source-map'', module: { loaders: [{ test: /\.(png|jpg)$/, loader: ''url?limit=8192&context=client&name=[path][name].[ext]'' }, { test: /\.scss$/, loader: ''style!css?sourceMap!resolve-url!sass?sourceMap'' }] }, plugins: [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ] }; module.exports = devConfig; 

这是一个包含多个entry的较复杂的例子。其中和webpack-hot-middleware有关的有两处。一是plugins的位置,增加3个插件,二是entry的位置,每一个entry后都增加一个hotMiddlewareScript

hotMiddlewareScript的值是webpack-hot-middleware/client?reload=true,其中?后的内容相当于为webpack-hot-middleware设置参数,这里reload=true的意思是,如果碰到不能hot reload的情况,就整页刷新。

在这个配置文件中,还有一个要点是publicPath不是/这样的值,而是http://localhost:3000/这样的绝对地址。这是因为,在使用?sourceMap的时候,style-loader会把css的引入做成这样:

style-loader的效果

这种blob的形式可能会使得css里的url()引用的图片失效,因此建议用带http的绝对地址(这也只有开发环境会用到)。有关这个问题的详情,你可以查看github上的issue。

Express启动文件部分

接下来是Express启动文件内添加以下代码:

var webpack = require(''webpack''),
    webpackDevMiddleware = require(''webpack-dev-middleware''), webpackHotMiddleware = require(''webpack-hot-middleware''), webpackDevConfig = require(''./webpack.config.js''); var compiler = webpack(webpackDevConfig); // attach to the compiler & the server app.use(webpackDevMiddleware(compiler, { // public path should be the same with webpack config publicPath: webpackDevConfig.output.publicPath, noInfo: true, stats: { colors: true } })); app.use(webpackHotMiddleware(compiler)); 

以上这段代码应该位于Express的routes代码之前。其中,webpack-dev-middleware配置的publicPath应该和webpack配置文件里的一致。

webpack-dev-middleware和webpack-hot-middleware的静态资源服务只用于开发环境。到了线上环境,应该使用express.static()

到此,client部分的目标就完成了。现在到网页里打开控制台,应该可以看到[HMR] connected的提示。这个项目中我只要求css使用HMR,如果你希望javascript也使用HMR,一个简单的做法是在entry文件内添加以下代码:

if(module.hot) {
    module.hot.accept(); } 

这样,与这个entry相关的所有.js文件都会使用hot reload的形式。关于这一点的更多详情,请参考hot module replacement。

接下来是server部分。

reload和supervisor

server部分的自动刷新,会面临一个问题:自动刷新的消息通知依靠的是浏览器和服务器之间的web socket连接,但在server部分修改代码的话,一般都要重启服务器来使变更生效(比如修改routes),这就会断开web socket连接。

所以,这需要一个变通的策略:浏览器这边增加一个对web socket断开的处理,如果web socket断开,则开启一个稍长于服务器重启时间的定时任务(setTimeout),相当于等到服务器重启完毕后,再进行一次整页刷新。

reload是一个应用此策略的组件,它可以帮我们处理服务器重启时的浏览器刷新。

现在,还差一个监听server文件,如果有变更就重启服务器的组件。参考reload的推荐,我们选用supervisor。

下面将reload和supervisor引入到Express项目内。

监听文件以重启服务器

通过以下代码安装supervisor(是的,必须-g):

npm install supervisor -g

然后,在package.json里设置新的scripts

"scripts": {
    "start": "cross-env NODE_ENV=dev supervisor -i client app"
}

这里的主要变化是从node app改为supervisor -i client app。其中-i等于--ignore,这里表示忽略client,显然,我们可不希望在改前端代码的时候服务器也重启。

这里的cross-env也是一个npm组件,它可以处理windows和其他Unix系统在设置环境变量的写法上不一致的问题。

把会重启的服务器和浏览器关联起来

把Express启动文件最后的部分做这样的修改:

var reload = require(''reload'');
var http = require(''http''); var server = http.createServer(app); reload(server, app); server.listen(3000, function(){ console.log(''App (dev) is now running on port 3000!''); }); 

Express启动文件的最后一般是app.listen()。参照reload的说明,需要这样用http再增加一层服务。

然后,再到Express的视图文件views里,在底部增加一个<script>

<% if (env !== "production") { %> <script src="/reload/reload.js"></script> <% } %> 

所有的views都需要这样一段代码,因此最好借助模板引擎用include或extends的方式添加到公共位置。

这里的reload.js和前面webpack的开发环境bundle.js并不冲突,它们一个负责前端源文件变更后进行编译和刷新,另一个负责在服务器发生重启时触发延时刷新。

到此,server也完成了。现在,修改项目内的任意源文件,按下ctrl + s,浏览器里的页面都会对应地做一次“适当”的刷新。

完整示例

完整示例已经提交到github:express-webpack-full-live-reload-example

效果如下:

示例效果

附加的可选方案

前面说的server部分,分为views和routes,如果只修改views,那么服务器并不需要重启,直接刷新浏览器就可以了。

针对这样的开发情景,可以把views文件的修改刷新变得更快。这时候我们不用reload和supervisor,改为用browsersync,在Express的启动文件内做如下修改:

var bs = require(''browser-sync'').create();
app.listen(3000, function(){ bs.init({ open: false, ui: false, notify: false, proxy: ''localhost:3000'', files: [''./server/views/**''], port: 8080 }); console.log(''App (dev) is going to be running on port 8080 (by browsersync).''); }); 

然后,使用browsersync提供的新的访问地址就可以了。这样,修改views(html)的时候,由browsersync帮忙直接刷新,修改css和javascript的时候继续由webpack的middleware来执行编译和刷新。

 

转载:https://segmentfault.com/a/1190000004505747

express制作小型热加载打包webpack--react篇

express制作小型热加载打包webpack--react篇

node 服务器的main.js文件

var opn = require('opn') // 打开浏览器
var path = require('path') // 路径模块
var express = require('express') // express框架 
var webpack = require('webpack') //核心模块webpack

var webpackConfig = require('./webpack.config')// 配置文件


var port = webpackConfig.devServer.port


var app = express()
var compiler = webpack(webpackConfig)

var devMiddleware = require('webpack-dev-middleware')(compiler, {
  publicPath: webpackConfig.output.publicPath,
//   quiet: true
})

var hotMiddleware = require('webpack-hot-middleware')(compiler, {
  log: false,
  heartbeat: 2000
})

app.use(require('connect-history-api-fallback')()) 
//开启 支持history路由


app.use(devMiddleware) // 服务器webpack插件


app.use(hotMiddleware) // 热加载自动打包


app.use('./static', express.static('./static'))

var uri = 'http://localhost:' + port

var _resolve
var readyPromise = new Promise(resolve => {
  _resolve = resolve
})

console.log('> Starting dev server...')
devMiddleware.waitUntilValid(() => {
  console.log('> Listening at ' + uri + '\n')
  
  if (process.env.NODE_ENV !== 'testing') {
    opn(uri)
  }
  _resolve()
})

var server = app.listen(port)

module.exports = {
  ready: readyPromise,
  close: () => {
    server.close()
  }
}

webpack配置文件

const path=require("path")
const HtmlWebpackPlugin=require("html-webpack-plugin")//用于把HTML页面放入内存
// const vueload=require("vue-loader/lib/plugin")
const minicss=require("mini-css-extract-plugin")//webpack4.0以后的打包css文件
const optimizecssassetswebpackplugin=require("optimize-css-assets-webpack-plugin")//压缩如果你使用ui组件库已经压缩的css就别必要了
const webpack = require("webpack")
const clernWebpackPlugin = require('clean-webpack-plugin')
const htmlplugin=new HtmlWebpackPlugin({
    template:path.join(__dirname,'./src/index.html'),//源头文件
    filename:"index.html",//生成首页的文件名称
    minify: {
        removeAttributeQuotes: true,
        collapseWhitespace: true
    }
})
const css=new minicss({//输出css独立文件
    filename:"./css/[name].css",
    chunkFilename:"[name].css"//或者id
})
module.exports={//webpack基于node构建的
    mode: "development", 
    entry: ['webpack-hot-middleware/client', './src/index.js'],  
    output: {
        filename: 'main.[hash:8].js',//通过热加载输出script文件挂载在目录与index.HTML一样
        path: path.resolve(__dirname, 'dist')
    },
    watch: true,
    watchOptions:{
        poll:1000,
        // aggregateTimeOut: 500,
        ignored: /node_modules/
    },
    //production 提供了约定大于配置 约定打包文件是src/index ->dist/main
    plugins:[
        htmlplugin,
    //    new vueload() ,
       css,
       new webpack.HotModuleReplacementPlugin()
    //    new clernWebpackPlugin('./dist')
     ],
    module: {//所以第三方模块的配置规则
        rules: [   
           
            {
                test: /\.js|.jsx$/,
                loader: 'babel-loader',
                exclude:/node_modules/
              },
              {
                test: /\.scss$/,
               
                
                use:[{loader:minicss.loader}, {
                    loader: 'css-loader',
                    options: { modules: true }
                  },'sass-loader']
              },
              {
                test: /\.tsx$/,
                loader: 'ts-loader',
                options: { appendTsSuffixTo: [/\.vue$/] },
                exclude:/node_modules/
              },
              {
                test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                  limit: 10000
                  
                }
              },
            // { test:/\.js|\jsx$/,use:[{loader:"babel-loader",options:{cacheDirectory:true}}],exclude:/node_modules/},//一个属性use:"babel-loader"两个是数组
            // // { test:/\.css/,use:['style-loader','css-loader']},
            {test:/\.css$/,use:[{loader:minicss.loader},'css-loader']},
         //     { test:/\.scss/,use:['style-loader',  {loader: "css-loader",
         //     options: {//这个是react的css模块化
         //        modules: {
         //            localIdentName: "[path][name]-[local]-[hash:5]"
         //        }//import css from '路径' console.log(css)会生成模块
         //        //这是react的处理办法 vue就是style里面写scoped
         //        //支持id与class 控制台输出的模块是健对值形式
         //     }//css scss less一样的配置模块化
         //    }]},
             { test:/\.(jpg|PNG|png|jpeg)/,use:[{loader:"url-loader",options:{
                 outputPath:"images/",
                 limit:1024,//单位是B 大于这个会打包出来
                 name:"[name].[ext]"
             }}]},                    
            //    { test:/.vue$/,use:[{loader:"vue-loader"}]},
               
           ]   
        },
        devtool:"source-map",//inline把js打包在一个文件里面 hidden分离出来 eval也是分离 
        // optimization:{//代码分割 下面vendors就是分割代码之后(把相同的库或者文件都提出来打包) 你可能在想css文件去哪了 你注销代码分割 你可以看见css文件夹
        //     splitChunks:{
        //         chunks:"all"
        //     }
        // },
        resolve: {
            // 将 `.ts` 添加为一个可解析的扩展名。
            extensions: ['.js','.jsx','.tsx','.json']
        },
        devServer: {
            port: 8080,
            hot: true,
            grogress: true,
            historyApiFallback: true 
            //true 表示webpack支持使用history false路由默认是hash
        }   
}

运行的index.js文件

import React from 'react'//创建组件虚拟dom 生命周期
import ReactDOM from 'react-dom'//把创建的组件虚拟dom放到页面上展示的
import Router from './router/router'
import {store} from './redux/redux' // 只有index才默认选中 
import {Provider} from '../node_modules/react-redux'
//import 'react-hot-loader'; 没有报错可以注释
import { hot } from 'react-hot-loader/root';
const App = () => <div>Hello World1!
        <Provider store={store}>
            <Router />,
        </Provider>,
</div>;
const Wpp = hot(App)
ReactDOM.render(
    <Wpp/>,
    document.getElementById("app")
)

babelrc

{
    "presets": ["env","stage-0","react"],
    "plugins": ["transform-runtime","react-hot-loader/babel"]
}

Express启动webpack打好的包

Express启动webpack打好的包

安装 Express

npm i express-generator -g
怎么安都行,安上就行

初始化一个项目

express 项目名
将打包后的代码,移动到public目录中

启动项目

npm i
npm run start

Express搭建在线便利贴——Webpack配置

Express搭建在线便利贴——Webpack配置

使用express应用生成器搭建项目

  1. 使用一下命令安装生成器

    $ npm install express-generator -g
  2. 使用-h 查看命令选项

    $ express -h
    
      Usage: express [options][dir]
    
      Options:
    
        -h,--help          output usage information
            --version       output the version number
        -e,--ejs           add ejs engine support
            --hbs           add handlebars engine support
            --pug           add pug engine support
        -H,--hogan         add hogan.js engine support
        -v,--view <engine> add view <engine> support (ejs|hbs|hjs|jade|pug|twig|            vash) (defaults to jade)
        -c,--css <engine>  add stylesheet <engine> support (less|stylus|compass|            sass) (defaults to plain css)
            --git           add .gitignore
        -f,--force         force on non-empty directory
  3. 创建名为node-sticky的express应用程序

    $ express --pug --css=less node-sticky//我默认安装了less和pug模板引擎
  4. 安装依赖

    $ cd node-sticky
    $ npm install
  5. 启动应用程序

    $ npm start
    
    > node-sticky@0.0.0 start /node-sticky
    > node ./bin/www
  6. 在浏览器输入localhost:3000 就可以看到欢迎画面了。
  7. 目前的目录结构

    ├── app.js
    ├── bin
    │   └── www
    ├── package.json
    ├── public
    │   ├── images
    │   ├── javascripts
    │   └── stylesheets
    │       └── style.css
    ├── routes
    │   ├── index.js
    │   └── users.js
    └── views
        ├── error.pug
        ├── index.pug
        └── layout.pug

添加src目录,配置相应的webpack

  1. 我们把前端的源码放在src目录下,使用webpack打包到node的public目录下面。添加之后的目录结构为:

    ├── app.js
    ├── bin
    |  └── www
    ├── package-lock.json
    ├── package.json
    ├── public
    |  ├── images
    |  ├── javascripts
    |  └── stylesheets
    |     └── style.less
    ├── routes
    |  ├── index.js
    |  └── users.js
    ├── src                          //前端源码目录
    |  ├── js
    |  |  ├── app                    //webpack入口目录
    |  |  |  └── index.js
    |  |  ├── lib                        //一些工具目录
    |  |  |—— module             //js模块
    |  ├── less                            //less目录
    |  └── webpack.config.js    //webpack配置文件
    └── views
       ├── error.pug
       ├── index.pug
       └── layout.pug
    我使用的mac的tree命令生成目录树,具体命令: tree -l 4 --ignore=node_modules,把依赖目录忽略。
  2. 配置webpack

    1. 配置之前需要先安装一下webpack依赖

      $ npm install webpack --save-dev
    2. 然后简单配置webpack入口文件和出口文件。

      let webpack = require('webpack')
      let path = require('path')
      
      module.exports = {
          entry: path.join(__dirname,'/js/app/index.js'),output: {
              path: path.join(__dirname,'../public'),filename: 'js/index.js'
          }
      }
    3. 在终端运行webpack

      $ cd src
      $ webpack
Version: webpack 4.3.0
Time: 265ms
Built at: 2018-3-29 05:21:58
      Asset       Size  Chunks             Chunk Names
js/index.js  676 bytes       0  [emitted]  main
Entrypoint main = js/index.js
   [0] ./js/module/b.js 36 bytes {0} [built]
   [1] ./js/module/a.js 36 bytes {0} [built]
   [2] ./js/app/index.js 65 bytes {0} [built]

    WARNING in configuration
    The 'mode' option has not been set. Set 'mode' option to 'development' or 'production' to enable defaults for this environment.
    ~~~
4. 最后给一个警告,要加上webpack运行的环境,在后面加上就好了

    ~~~
    $ webpack --mode development
    ~~~

配置package.json的script脚本

  1. 但是我们不能一直在src里面执行,我们要在根目录下执行,所有要使用package.json里面的srcipt字段脚本命令。需要配置webpack的--config指定脚本文件。

    //package.json
    {
      "name": "node-sticky","version": "0.0.0","private": true,"scripts": {
        "start": "node ./bin/www","webpack": "webpack --config=src/webpack.config.js --mode=development"
      },"dependencies": {
        "cookie-parser": "~1.4.3","debug": "~2.6.9","express": "~4.16.0","http-errors": "~1.6.2","less-middleware": "~2.2.1","morgan": "~1.9.0","pug": "2.0.0-beta11","webpack": "^4.3.0"
      }
    }
  2. 然后进入个目录执行npm run webpack就会发现报错了。

    $ cd ..
    $ npm run webpack                                                                                                            
    
    > node-sticky@0.0.0 webpack /Users/lanbo/projects/node-sticky
    > webpack --config=src/webpack.config.js
    
    The CLI moved into a separate package: webpack-cli.
    Please install 'webpack-cli' in addition to webpack itself to use the CLI.
    -> When using npm: npm install webpack-cli -D
    -> When using yarn: yarn add webpack-cli -D
    npm ERR! code ELIFECYCLE
    npm ERR! errno 1
    npm ERR! node-sticky@0.0.0 webpack: `webpack --config=src/webpack.config.js`
    npm ERR! Exit status 1
    npm ERR!
    npm ERR! Failed at the node-sticky@0.0.0 webpack script.
    npm ERR! This is probably not a problem with npm. There is likely additional                 logging output above.
    
    npm ERR! A complete log of this run can be found in:
    npm ERR!     /Users/lanbo/.npm/_logs/2018-03-28T21_33_04_687Z-debug.log
  3. 根据报错内容需要安装webpack-cli,那就照着做吧。

    $ npm install webpack-cli --save-dev
  4. 然后再次执行,就发现成功啦,哈哈哈~~然后问题来了,不能每次都要自己手动去webpack,有一个工具能自动去打包就好了,正好有这个工具--onchange.

    $ npm install onchange --save-dev
  5. 配置script脚本

    $ "watch": "onchange 'src/**/*.js' 'src/**/*.less' -- npm run webpack"
  6. 在另外开一个终端,启动脚本就不去管他了,js和less文件有变动会自动去打包。

    $ npm run watch

一点点记录,一步步成长,加油~~~~

关于详解webpack+express多页站点开发webpack多页应用的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于express_webpack自动刷新、express制作小型热加载打包webpack--react篇、Express启动webpack打好的包、Express搭建在线便利贴——Webpack配置等相关内容,可以在本站寻找。

本文标签: