在用webpack打包的時候,咱們常常遇到一個問題,那就是因爲path的設置,致使咱們不能分目錄打包咱們想要的文件,這樣的問題怎麼辦呢?
其實這樣的問題很好解決。咱們只須要在entry裏作一些改變便可。css
以咱們的項目爲例。我須要對資源生成一張資源地圖,按照資源地圖來製做入口配置。html
var path = require('path'); function getSourceMap(list) { var entry = Object.create(null); list.forEach(function (src) { // 砍掉./static/前綴和.extname後綴 // 咱們的項目結構,讀者能夠自行配置,不用拘泥於僞代碼 entry[src.slice(9, src.lastIndexOf('.'))] = src; }); return entry; }
生成的資源入口最終變成了前端
entry = { 'market/js/pages/appIndexPage': './static/market/js/pages/appIndexPage.js', 'market/js/pages/appOrderPage': './static/market/js/pages/appOrderPage.js' ... }
這時候,只要簡單的將輸入靜態資源的出口規定好,咱們的多出口輸出配置就完成了node
output: { path: path.resolve(__dirname, 'www/static-mobile/' + version), filename: "[name].js" }
最終輸出的文件結構以下webpack
+www +static-mobile +dev +market + js +pages appIndexPage.js appOrderPage.js ....
本地構建的過程當中,咱們的webpackDevServer其實只充當着靜態資源服務器的角色。這個時候咱們就不可避免的要訪問thinkjs的服務來支撐每一個頁面的展現。nginx
怎麼辦呢?若是啓用nginx,對於前端來講,又是一坨沒有接觸過的東西,不如用咱們熟悉的東西來作。es6
var d = webpack(options); var WebpackDevServer = require('webpack-dev-server'); var compiler = webpack(options); var server = new WebpackDevServer(compiler, { contentBase:path.join(__dirname, 'www/'), compress: true, hot: true, open: true, stats: { colors: true } , proxy: [ { path: '/static\-mobile', target: 'http://localhost:3000', pathRewrite: { '^/static-mobile': '/qietv-mobile' } }, { path: '*', target: 'http://localhost:8361', context: function (pathname, req) { if (/^\/(static\-mobile|qietv\-mobile)/.test(pathname)) { return false; } return true; }, } ] });
咱們所處的項目的thinkjs服務端口是8361,其實只要將非靜態文件夾所有轉到thinkjs服務上就行。在網上有不少其餘答案,會告訴你只用跟着他的答案寫就好了,卻沒有告訴你爲何。要搞清楚proxy的詳細配置方法,仍是須要去看webpack-dev-server的文檔和http-proxy-middleware的文檔(由於devServer使用的是http-proxy-middleware)。web
同窗們可能會疑惑,我啓動了devServer.hot = true,入口也填入了webpack-dev-server/client,plugin也插入了,依然找不到文件,爲何?這個問題在於publicPath設置的錯誤(publicPath須要和output.publicPath一致)json
var server = new WebpackDevServer(compiler, { contentBase:path.join(__dirname, 'www/'), compress: true, hot: true, inline: true, // publicPath不填默認是'/', // 在這裏不填的話,咱們本來輸出到./www/qietv-mobile/dev/client/js/app.js // 訪問的時候就變成了 'http://localhost:3000/client/js/app.js'才訪問獲得. // 加上一個訪問path,就能夠成功寫出了。 // publicPath: "/qietv-mobile/" + version + '/' }
在設置完publicPath之後記得在pulgin里加入new webpack.HotModuleReplacementPlugin()。除此以外,你還須要在入口文件裏容許須要的模塊熱更新才行。服務器
// 容許全部子模塊熱更新 if (module.hot) { module.hot. accept(); // 只容許某一個模塊熱更新 // module.hot. accept('./a'); // 容許多個指定模塊熱更新 // module.hot. accept(['./a', './b']); }
可是開發的時候,咱們並非很想寫這個東西對吧,因此此時咱們能夠藉助插件webpack-module-hot-accept(這個插件是一個loader,用於給通過的js增長一個module.hot.accept(xxx)的包裝)。用法請自行百度該插件
咱們有這麼一種需求,須要將jade文件觀察(jade並不禁咱們的webpack引入),此時若是jade更新,咱們須要刷新頁面。做爲一個懶人咱們又懶得按下f5去刷新,這時候怎麼辦呢?
var webpack = require('webpack'); var config = require('./webpack.config.js'); var webpackDevServer = require('webpack-dev-server'); var server = webpackDevServer(webpack(config), { // someoptions }); var fs = require('fs-extra'); // 僞代碼, watch('/watchedDir', function (event) { if (event.filepath.test(/\.jade$/)) { fs.copy(event.filepath, targetDist) .then(function () { server.sockWrite(server.sockets, "content-changed"); }) } })
webpack-dev-server向外暴露了sockWrite接口,用於指揮開發頁面執行一些命令(webpack-dev-server使用sockjs和頁面進行通訊)。當發佈content-changed事件的時候,頁面接收到,會被直接刷新。由於content-changed事件對應的操做以下(入口應加入webpack-dev-server/client):
"content-changed": function() { log("info", "[WDS] Content base changed. Reloading...") self.location.reload(); },
若是咱們的頁面上有一些資源並不須要編譯,僅僅只是簡單的移動一下位置,那麼咱們簡單作一個快捷方式過去就好了。。。這樣能夠省卻本地開發複製移動這種無聊的事。。。
var views = glob.sync(path.resolve(p, '**/views')); views.forEach(function (viewSrc) { fs.ensureSymlinkSync(viewSrc, path.resolve(__dirname, 'view', viewSrc.match(/\/([a-zA-Z0-9\-]+)\/views$/)[1])); });
我跟你說這個只是個符號鏈接,當心你操做文件的時候把文件搞空了。
實際上,happypack是爲了解決大量計算速度上不來的問題。咱們作文件移動,複製,這些事情的時候基本用不上。那何時用呢?首先咱們要明白happypack究竟是什麼東西。happypack自己管理了一些線程,充分利用cpu來說計算密集的事情時間縮短(事實上他這個說法有誤,他用的是chird_process,使用的是子進程,通訊用的是IPC,固然應該是進程池。可是你們寫這種東西習慣性的取這種名字,那就這樣咯)。咱們在作什麼事情的時候會用到cpu計算呢?在解析es6文本,解析其餘預編譯語言的時候,就會用到cpu進行計算。因此在這種時候,咱們須要上happypack進行構建。
happypack參與構建的姿式參考如下片斷
// 例子是掘金上挖過來的,webpack1的寫法,見諒 var babelQuery = webpackConfig.babel; // 這個size可使用cpu num + 1進行代替 var happyThreadPool = HappyPack.ThreadPool({ size: 25 }); function createHappyPlugin(id, loaders) { console.log('id', id) return new HappyPack({ id: id, loaders: loaders, threadPool: happyThreadPool, // disable happy caching with HAPPY_CACHE=0 cache: true, // make happy more verbose with HAPPY_VERBOSE=1 verbose: process.env.HAPPY_VERBOSE === '1', }); } webpackConfig.module = {}; webpackConfig.module = { loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'happypack/loader?id=js', }, { test: /\.jsx$/, loader: 'happypack/loader?id=jsx', }, { test(filePath) { return /\.css$/.test(filePath) && !/\.module\.css$/.test(filePath); }, loader: ExtractTextPlugin.extract('style', 'happypack/loader?id=cssWithoutModules') }, { test: /\.module\.css$/, loader: ExtractTextPlugin.extract('style', 'happypack/loader?id=cssWithModules') }, { test(filePath) { return /\.less$/.test(filePath) && !/\.module\.less$/.test(filePath); }, loader: ExtractTextPlugin.extract('style', 'happypack/loader?id=lessWithoutModules') }, { test: /\.module\.less$/, loader: ExtractTextPlugin.extract('style', 'happypack/loader?id=lessWithModules') } ], } if (!!handleFontAndImg) { webpackConfig.module.loaders.concat([ { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'happypack/loader?id=woff' }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'happypack/loader?id=woff2' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'happypack/loader?id=ttf' }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'happypack/loader?id=eot' }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'happypack/loader?id=svg' }, { test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i, loader: 'happypack/loader?id=img' }, { test: /\.json$/, loader: 'happypack/loader?id=json' }, { test: /\.html?$/, loader: 'happypack/loader?id=html' } ]) } else { webpackConfig.module.loaders.concat([ { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff' }, { test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/font-woff' }, { test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=application/octet-stream' }, { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file' }, { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&minetype=image/svg+xml' }, { test: /\.(png|jpg|jpeg|gif)(\?v=\d+\.\d+\.\d+)?$/i, loader: 'url?limit=10000' }, { test: /\.json$/, loader: 'json' }, { test: /\.html?$/, loader: 'file?name=[name].[ext]' } ]) } webpackConfig.plugins.push(createHappyPlugin('js', ['babel?'+JSON.stringify(babelQuery)])) webpackConfig.plugins.push(createHappyPlugin('jsx', ['babel?'+JSON.stringify(babelQuery)])) webpackConfig.plugins.push(createHappyPlugin('cssWithoutModules', ['css?sourceMap&-restructuring!postcss'])) webpackConfig.plugins.push(createHappyPlugin('cssWithModules', ['css?sourceMap&-restructuring&modules&localIdentName=[local]___[hash:base64:5]!postcss'])) webpackConfig.plugins.push(createHappyPlugin('lessWithoutModules', ['css?sourceMap!postcss!less-loader?sourceMap'])) webpackConfig.plugins.push(createHappyPlugin('lessWithModules', ['css?sourceMap&modules&localIdentName=[local]___[hash:base64:5]!postcss!less-loader?sourceMap'])) if (!!handleFontAndImg) { webpackConfig.plugins.push(createHappyPlugin('woff', ['url?limit=10000&minetype=application/font-woff'])) webpackConfig.plugins.push(createHappyPlugin('woff2', ['url?limit=10000&minetype=application/font-woff'])) webpackConfig.plugins.push(createHappyPlugin('ttf', ['url?limit=10000&minetype=application/octet-stream'])) webpackConfig.plugins.push(createHappyPlugin('eot', ['file'])) webpackConfig.plugins.push(createHappyPlugin('svg', ['url?limit=10000&minetype=image/svg+xml'])) webpackConfig.plugins.push(createHappyPlugin('img', ['url?limit=10000'])) webpackConfig.plugins.push(createHappyPlugin('json', ['json'])) webpackConfig.plugins.push(createHappyPlugin('html', ['file?name=[name].[ext]'])) }
本地開發追求的是開發速度,並不須要全量構建,甚至能夠說,咱們只須要指定子目錄運行webpackdev便可。在啓動本地開發的構建服務的時候,最初只會構建一次,用於訪問其餘項目模塊使用。這樣的代碼是修改其餘模塊並不會被watch,但咱們追求的是開發一個模塊就專心一個模塊的開發便可。這樣才能十分明顯的提升效率。
有這麼一個經典的場景,a君問:
module: { loaders: [ {//抽離css test: /\.css$/, loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader', publicPath: '/dist/' }) }
我代碼這樣寫用了ExtractTextPlugin爲啥更新不了啊!
首先要說,webpack官方直接就告訴你了,咱們在開發環境下,不推薦你用ExtractTextPlugin。由於1是開發環境不須要考慮加載速度和鏈接數量,2是ExtractTextPlugin這個插件也是將option合併之後返回給webpack進行處理,自己輸出的非js模塊,不支持熱替換。這種狀況下直接使用其餘loader打包成js明顯纔是正道(支持熱更新了)。在進行全量構建或者輸出構建的時候再將css添加進去會比較明智。