Webpack Project Configuration的示例分析

发布时间:2021-03-01 11:18:09 作者:小新
来源:亿速云 阅读:174

这篇文章主要介绍Webpack Project Configuration的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

Webpack Project Configuration

Github Repository

本部分假设你已经对Webpack有了大概的了解,这里我们会针对笔者自己在生产环境下使用的Webpack编译脚本进行的一个总结,在介绍具体的配置方案之前笔者想先概述下该配置文件的设计的目标,或者说是笔者认为一个前端编译环境应该达成的特性,这样以后即使Webpack被淘汰了也可以利用其他的譬如JSPM之类的来完成类似的工作。

在发布版本中,可能需要一些特殊的配置或者插件,譬如只有在 NODE_ENV环境变量等于 production的情况下才会有逻辑配置需要添加在配置文件中,那么在Webpack的配置文件中可以使用如下定义:

var webpack    = require('webpack');
var production = process.env.NODE_ENV === 'production';
var plugins = [    
new webpack.optimize.CommonsChunkPlugin({        
name:      'main', // Move dependencies to our main file        
children:  true, // Look for common dependencies in all children,        
minChunks: 2, // How many times a dependency must come up before being extracted    }),];
if (production) {    
plugins = plugins.concat([       // Production plugins go here    ]);
}module.exports = {    
entry:   './src',    
output:  {       
 path:       'builds',        
 filename:   'bundle.js',        
 publicPath: 'builds/',    },    
 plugins: plugins,    // ...};

在发布版本中,Webpack的一些配置可以被关闭,譬如:

module.exports = {    
debug:   !production,    
devtool: production ? 
false : 'eval',

Configuration

package.jso

{  
"name": "webpack-boilerplate",  
"version": "1.0.0",  
"description": "Page-Driven Webpack Boilerplate For React-Redux Work Flow",  
"scripts": {    
"start": "node devServer.js?7.1.29",    
"storybook": "start-storybook -p 9001",    
"build:webpack": "NODE_ENV=production webpack -p --config webpack.config.js?7.1.29",    
"build": "npm run clean && npm run build:webpack",    
"build:style-check": "NODE_ENV=production CHECK=true webpack -p --config webpack.config.js?7.1.29",    
"deploy": "npm run build && ./node_modules/.bin/http-server dist",    
"clean": "rimraf dist",    
"lint": "eslint src"  
},  
"repository": {    
"type": "git",    
"url": "https://github.com/wxyyxc1992/Webpack-React-Redux-Boilerplate"  
},  
"keywords": [    
"boilerplate",    
"live",    
"hot",    
"reload",    
"react",    
"reactjs",    
"hmr",    "edit",    "webpack",    "babel",    "react-transform",    "PostCSS(FlexBox Polyfill)"  
],  
"author": "Chevalier (http://github.com/wxyyxc1992)",  
"license": "MIT",  
"bugs": {    
"url": "https://github.com/wxyyxc1992/Webpack-React-Redux-Boilerplate/issues"  
},  
"homepage": "https://github.com/wxyyxc1992/Webpack-React-Redux-Boilerplate",  
"devDependencies": {    
"@kadira/storybook": "^1.17.1",    ...  },  
"dependencies": {    "boron": "^0.1.2",    ...  
}
}

webpack.config.js

var path = require('path');
var webpack = require('webpack');
//PostCSS pluginsvar autoprefixer = require('autoprefixer');
//webpack pluginsvar ProvidePlugin = require('webpack/lib/ProvidePlugin');
var DefinePlugin = require('webpack/lib/DefinePlugin');
var CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var WebpackMd5Hash = require('webpack-md5-hash');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var NODE_ENV = process.env.NODE_ENV || "develop";//获取命令行变量
//@region 可配置区域//定义统一的Application,不同的单页面会作为不同的Application
/** 
* @function 开发状态下默认会把JS文本编译为main.bundle.js,然后使用根目录下dev.html作为调试文件. 
* @type {*[]} 
*/
var apps = [    
{        
//required        
id: "index",
//编号        
title: "Index",//HTML文件标题        
entry: {            
name: "index",//该应用的入口名            
src: "./src/index.js?7.1.29",//该应用对应的入口文件        
},//入口文件        
indexPage: "./src/index.html",//主页文件        
//optional        
dev: false,//判断是否当前正在调试,默认为false        
compiled: true//判斷當前是否加入编译,默认为true    
},    
{        
id: "helloworld",        
title: "HelloWorld",        
entry: {            
name: "helloworld",            
src: "./src/modules/helloworld/container/app.js?7.1.29"        },        
indexPage: "./src/modules/helloworld/container/helloworld.html",        
dev: false,        compiled: true    },    
{        
id: "todolist",        
title: "TodoList",        
compiled: false    },    {        
//required        
id: "counter",//编号        
title: "Counter",//HTML文件标题        
entry: {            
name: "counter",//该应用的入口名            
src: "./src/modules/counter/container/app.js?7.1.29",//该应用对应的入口文件        
},//入口文件        
indexPage: "./src/modules/counter/container/counter.html",//主页文件        
//optional        
dev: false,//判断是否当前正在调试,默认为false        
compiled: true//判斷當前是否加入编译,默认为true    
},    {        
//required        
id: "form",//编号        
title: "Form",//HTML文件标题        
entry: {            
name: "form",//该应用的入口名            
src: "./src/modules/form/form.js?7.1.29"//该应用对应的入口文件        
},//入口文件        
indexPage: "./src/modules/form/form.html",//主页文件        
//optional        
dev: true,//判断是否当前正在调试,默认为false        
compiled: true//判斷當前是否加入编译,默认为true    
}];//定义非直接引用依赖//定义第三方直接用Script引入而不需要打包的类库//使用方式即为
var $ = require("jquery")const externals = {    
jquery: "jQuery",    pageResponse: 'pageResponse'};
/*********************************************************/
/*********************************************************/
/*下面属于静态配置部分,修改请谨慎*/
/*********************************************************/
/*********************************************************/
//开发时的入口考虑到热加载,只用数组形式,即每次只会加载一个文件
var devEntry = [    'eventsource-polyfill',    'webpack-hot-middleware/client',];
//生产环境下考虑到方便编译成不同的文件名,所以使用数组
var proEntry = {    "vendors": "./src/vendors.js?7.1.29",//存放所有的公共文件};
//定义HTML文件入口,默认的调试文件为src/index.htmlvar htmlPages = [];
//遍历定义好的app进行构造
apps.forEach(function (app) {    
//判断是否加入编译    
if (app.compiled === false) {        
//如果还未开发好,就设置为false        
return;    
}    
//添加入入口    
proEntry[app.entry.name] = app.entry.src;   
//构造HTML页面    
htmlPages.push({        
filename: app.id + ".html",        
title: app.title,        
// favicon: path.join(__dirname, 'assets/images/favicon.ico'),        
template: 'underscore-template-loader!' + app.indexPage, //默认使用underscore        
inject: false, // 使用自动插入JS脚本,        
chunks: ["vendors", app.entry.name] //选定需要插入的chunk名    
});    
//判断是否为当前正在调试的    
if (app.dev === true) {        
//如果是当前正在调试的,则加入到devEntry        
devEntry.push(app.entry.src);    
}});//@endregion 可配置区域//基本配置
var config = {    
devtool: 'source-map',    
//所有的出口文件,注意,所有的包括图片等本机被放置到了dist目录下,其他文件放置到static目录下    
output: {        
path: path.join(__dirname, 'dist'),//生成目录       
 filename: '[name].bundle.js',//文件名        
 sourceMapFilename: '[name].bundle.map'//映射名        
 // chunkFilename: '[id].[chunkhash].chunk.js',//块文件索引    },   
  //配置插件    
  plugins: [        
  // new WebpackMd5Hash(),//计算Hash插件        
  new webpack.optimize.OccurenceOrderPlugin(),        
  new webpack.DefinePlugin({            
  'process.env': {                
  //因为使用热加载,所以在开发状态下可能传入的环境变量为空                
  'NODE_ENV': process.env.NODE_ENV === undefined ? JSON.stringify('develop') : JSON.stringify(NODE_ENV)            },            //判断当前是否处于开发状态            __DEV__: process.env.NODE_ENV === undefined || process.env.NODE_ENV === "develop" ? JSON.stringify(true) : JSON.stringify(false)        }),        //提供者fetch Polyfill插件        new webpack.ProvidePlugin({            // 'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'        }),        //提取出所有的CSS代码        new ExtractTextPlugin('[name].css'),        //自动分割Vendor代码        new CommonsChunkPlugin({name: 'vendors', filename: 'vendors.bundle.js', minChunks: Infinity}),        //自动分割Chunk代码        new CommonsChunkPlugin({            children: true,            async: true,        })    ],    module: {        loaders: [            {                test: /\.(js|jsx)$/,                exclude: /(libs|node_modules)/,                loader:"babel",                query: {                    presets: ["es2015", "react", "stage-2"],                    plugins: [                        ["typecheck"],                        ["transform-flow-strip-types"],                        ["syntax-flow"],                        ["transform-class-properties"],                        ["transform-object-rest-spread"]                    ]                }            },            {                test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,                loader: 'url-loader?limit=8192&name=assets/imgs/[hash].[ext]'            },// inline base64 URLs for <=8k images, direct URLs for the rest            {                test: /\.vue$/,                loader: 'vue'            }        ]    },    postcss: [        autoprefixer({browsers: ['last 10 versions', "> 1%"]})    ],//使用postcss作为默认的CSS编译器    resolve: {        alias: {            libs: path.resolve(__dirname, 'libs'),            nm: path.resolve(__dirname, "node_modules"),            assets: path.resolve(__dirname, "assets"),        }    }};//进行脚本组装config.externals = externals;//自动创建HTML代码htmlPages.forEach(function (p) {    config.plugins.push(new HtmlWebpackPlugin(p));});//为开发状态下添加插件if (process.env.NODE_ENV === undefined || process.env.NODE_ENV === "develop") {    //配置SourceMap    config.devtool = 'cheap-module-eval-source-map';    //设置入口为调试入口    config.entry = devEntry;    //設置公共目錄名    config.output.publicPath = '/dist/'//公共目录名    //调试状态下的CSS    config.module.loaders.push({        test: /\.(scss|sass|css)$/,        loader: 'style-loader!css-loader!postcss-loader!sass'    });    //添加插件    config.plugins.push(new webpack.HotModuleReplacementPlugin());    config.plugins.push(new webpack.NoErrorsPlugin());} else {    //如果是生产环境下    config.entry = proEntry;    //如果是生成环境下,将文件名加上hash    config.output.filename = '[name].bundle.js.[hash:8]';    //設置公共目錄名    config.output.publicPath = '/'//公共目录名    //发布状态下添加Loader    config.module.loaders.push({        test: /\.(scss|sass|css)$/,        loader: ExtractTextPlugin.extract('style-loader', 'css-loader!postcss-loader!sass')    });    //添加代码压缩插件    config.plugins.push(        new webpack.optimize.UglifyJsPlugin({            compressor: {                warnings: false            }        }));    //添加MD5计算插件    //判断是否需要进行检查    if (process.env.CHECK === "true") {        config.module.loaders[0].loaders.push("eslint-loader");    }}module.exports = config;

devServer.js

var path = require('path');
var express = require('express');
var webpack = require('webpack');//默认是开发时配置
var config = require('./webpack.config');
var app = express();
var compiler = webpack(config);
app.use(require('webpack-dev-middleware')(compiler, {  noInfo: true,  publicPath: config.output.publicPath}));
app.use(require('webpack-hot-middleware')(compiler));
app.get('*', function(req, res) {  res.sendFile(path.join(__dirname + "/src/", "dev.html"));});//监听本地端口
app.listen(3000, 'localhost', function(err) {  
if (err) {    
console.log(err);    
return;  
}  
console.log('Listening at http://localhost:3000');});

Deployment

开始这个小节之前,可以先看下大神的一篇文章: 大公司里怎样开发和部署前端代码。

对于静态文件,第一次获取之后,文件内容没改变的话,浏览器直接读取缓存文件即可。那如果缓存设置过长,文件要更新怎么办呢?嗯,以文件内容的 MD5 作为文件名就是一个不错的解决方案。来看下用 webpack 应该怎样实现

output: {    
path: xxx,   
 publicPath: yyy,    
 filename: '[name]-[chunkhash:6].js'}

打包后的文件名加入了 hash 值

const bundler = webpack(config)bundler.run((err, stats) => {  
let assets = stats.toJson().assets  let name  for (let i = 0; 
i < assets.length; i++) {    
if (assets[i].name.startsWith('main')) {      
name = assets[i].name      
break    
}  
}  fs.stat(config.buildTemplatePath, (err, stats) => {    
if (err) {      
fs.mkdirSync(config.buildTemplatePath)    
}    writeTemplate(name)  
})
})

手动调用 webpack 的 API,获取打包后的文件名,通过 writeTemplate更新 html 代码。完整代码猛戳 gitst。这样子,我们就可以把文件的缓存设置得很长,而不用担心更新问题。

以上是“Webpack Project Configuration的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!

推荐阅读:
  1. 小程序错误TypeError: __webpack_require__
  2. Webpack快速入门(一)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

webpack

上一篇:Thymeleaf2迁移到Thymeleaf3的示例分析

下一篇:Python3压缩和解压缩的实现方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》