webpack做文件合并
使用构建工具非常常用一个功能就是合并js和css文件,gulp和grunt都是编写相应的任务来完成,转到webpack突然懵逼了,简单的项目怎么做文件合并呢?其实只需把多个js文件同时引入到main.js(入口文件)中即可,css借助extract-text-webpack-plugin搞定。
不管是简单的纯展示页面还是复杂的单页或多页面,webpack差不多可以彻底取代gulp、grunt了,利用file、scss、pug、babel等各种loader处理各种需求比grunt那种编写任务型的配置方便太多。
webpack非常智能,多次引入相同模块,最终打包后只会包含一次。如果你不想打包某个模块,在webpack.config.js里配置externals即可。对于css模块,externals是无效的,js里不引入,直接在html里放link就好了,不要陷入webpack的魔障。对于一些老旧的jq插件,可以配置providePlugin或使用expose-loader,用法就自行google了。熟悉了之后,各种新旧项目,大小项目都能用webpack耍的飞起。
// webpack.config.js
// ...
externals: {
'vue': 'Vue',
'jquery': 'jQuery',
},
webpack-dev-server跨域设置
开发的时候经常有跨域需求,前端跨域方法虽然很多,但是只是为了开发时用用,感觉没一个好用的。利用webpack-dev-server可以轻松解决开发时跨域问题,devServer启动了一个node服务器帮你代理请求,详细配置请看proxy,这个设置是将所有以/api开头的路由映射到xxx.com,target记得带上协议名哦(http://)。pathRewrite就是将/api/a路径重写为/a。当然你也可以配置为/转发请求,这样静态资源也可以在localhost下请求到了。跨域的前提是服务器上配置了'Access-Control-Allow-Origin:*',开发时服务器端一般都设置了。
// webpack.config.js
// ...
devServer: {
port: 8888,
historyApiFallback: true,
stats: 'minimal', // 输入精简信息
overlay: true, // 将错误显示在html之上
proxy: {
'/api': {
target: 'http://xxx.com',
secure: false,
changeOrigin: true,
// pathRewrite: {'^/api': ''},
}
}
},
webpack-dev-server热更新失效
自从用了webpack-dev-server,我的f5键长舒一口气,不过有时候碰到webpack-dev-server热更新回失效,一般是配置出了问题。只需在pulugins里添加HotModule插件,devServer不要配置hot:true了,虽然文档里写的是设置hot:true开启热更新,但是我试过配置hot热更新就失效了,不解!
// webpack.config.js
// ...
plugins: [
new webpack.HotModuleReplacementPlugin(), // 热加载
]
2017.9.30更新:
webpack文档里写的是命令行加上 -hot 启用热更新模式,不用手动加hrm plugin。
使用extract-text-webpack-plugin和html模版(例如:art-template)时,修改html和css不会触发热更新,只有js变动可以触发。因为这些loader没有实现hmr相关api,可以通过安装css-hot-loader等来hack
有个简便方法,配置devServer:watchContentBase: true,开启watch模式,文件有改动就会触发自动刷新,虽然性能稍差。
使用pug(jade)作为vue文件中的html模板
npm安装pug,记住不是pug-loader,也不用配置vue-loader,只需在template标签中指定lang=pug,就可以愉快的使用pug语法了,比起html看起来简洁多了。
header
.logo
h1 我是头部
html-webpack-plugin在多页面中的妙用
以前只用webpack写单页引用,index.html就是个空壳,后来也有一些纯展示页面,包含多个html文件,也想用webpack,毕竟各种loader太好用了。这时候就需要好好利用html-webpack-plugin了。直接上一个webpack配置,基于vue-simple的webpack配置做了些修改,同时参考了歪闹大神的webpack多页面教程,利用glod获取文件名,自动生成html-webpack-plugin配置,so geek!利用pug写html,scss写css,作为一个页面仔,也不那么无聊了,效率也是杠杠滴。
let path = require('path');
let webpack = require('webpack');
let ExtractTextPlugin = require('extract-text-webpack-plugin');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let glob = require('glob');
// js名必须与html的fileName对应
let entry = (() => {
let obj = {};
getEntry('src/views/pages/*.pug').forEach(fileName => {
obj[fileName] = './src/js/' + fileName + '.js';
});
return obj;
})();
module.exports = {
entry: entry,
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'js/[name].js',
// chunkFilename: 'js/[name][id].chunk.js', // 公共代码块
},
externals: {
// 'vue': 'Vue',
// 'jquery': 'jQuery',
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
scss: ExtractTextPlugin.extract({
fallback: 'vue-style-loader',
use: 'css-loader!sass-loader',
}),
}
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
// 不要使用options配置url-loader webpack会报错
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader?limit=10000&name=img/[name].[hash:7].[ext]',
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'file-loader?limit=10000&name=img/[name].[hash:7].[ext]',
},
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader!postcss-loader!sass-loader'
})
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader!postcss-loader'
})
},
{
test: /\.html$/,
loader: 'html-loader?attrs=img:src img:data-src'
},
{
test: /\.pug$/,
loader: 'pug-loader'
},
]
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {}
},
devServer: {
port: 8888,
historyApiFallback: true,
stats: 'minimal', // 输入精简信息
overlay: true, // 将错误显示在html之上
proxy: {
'/api': {
target: 'http://localhost:9999',
secure: false,
changeOrigin: true,
// pathRewrite: {'^/api': ''},
}
}
},
performance: {
hints: false
},
devtool: '#eval-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(), // 热加载
// new webpack.ProvidePlugin({
// $: 'jquery',
// jQuery: 'jquery',
// }),
new ExtractTextPlugin('css/[name].css'), //单独使用link标签加载css并设置路径,相对于output配置中的publicPath
],
};
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map';
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}
// 自动生htmlPlugins
getEntry('src/views/pages/*.pug').forEach(fileName => {
let conf = {
filename: fileName + '.html', //生成的html存放路径,相对于path
template: 'src/views/pages/' + fileName + '.pug', //html模板路径
inject: true,
hash: true,
minify: {
removeComments: true,
minifyJS: true,
},
chunks: [fileName],
};
module.exports.plugins.push(new HtmlWebpackPlugin(conf));
});
// 获取文件名函数
function getEntry(viewsPath) {
let files = glob.sync(viewsPath);
let entries = [];
let entry, basename, extname;
for (let i = 0; i < files.length; i++) {
entry = files[i];
extname = path.extname(entry); // 扩展名 eg: .html
basename = path.basename(entry, extname); // eg: index
entries.push(basename);
}
return entries;
}
路径 —— alias别名和~的使用
alias:{
'@': path.resolve(__dirname, 'src')
}
import路径中使用别名是一个很好的实践,将@指向src,我们import的时候以@/开头,在各层目录里就能用各种../
如果你想在css或html使用@,请在前面加上~告诉webpack用require处理他。
例如在是scss里导入其他node_modules里的css文件 @import "~swiper/dist/css/style.css"
例如在是scss里导入其他src下的css文件 @import "~@/css/mixin.css"