Next.js 笔记
<div class="main-body"><p>NEXT 中文文档地址!</p>
<ol>
<li>next.js 只有服务端使用的包需要做单独处理,无需打包到项目中,可以使用@zeit/next-bundle-analyzer观察代码。</li>
<li>Router.beforePopState() 截断Router操作的设置只有在客户端生效(需在componentDidMount中设置)且进入此函数中的方法只有Router栈中有值的时候才可以!</li>
<li>next.js 中设置绝对路径的方法是在next.config.js中wepack方法中的config参数增加配置。</li>
<li>next.js 中配置自定义接口可以使用自定义启动参数,创建 server.js 通过 node server.js 启动。</li>
<li>next.js 支持IE11和各主流浏览器 IE11以内的IE版本不支持。</li>
<li>Link 标签passHref属性可以强制给子元素传递href属性,有利于SEO优化。</li>
<li>windows 不支持 NODE_ENV=development的设置方式 导入 cross-env 然后运行时在前面添加 cross-env 即可解决。</li>
<li>webpack 配置自定义的时候覆盖配置需要继承本有的配置,否则会使 next 解析错误(analysis error)。
<div class="cnblogs_code">
<pre>module.exports =<span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ... other next.js config</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {
webpack: config </span>=><span style="color: rgba(0, 0, 0, 1)"> {
config.resolve.alias </span>=<span style="color: rgba(0, 0, 0, 1)"> {
...(config.resolve.alias </span>||<span style="color: rgba(0, 0, 0, 1)"> {}),
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> custom webpack aliases</span>
<span style="color: rgba(0, 0, 0, 1)"> }
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> config
}
}
}</span></pre>
</div>
</li>
<li>null-loader 加载器的一个用途是关闭依赖项导入的模块。 例如,你的项目依赖于导入你不需要的polyfill的ES6库,因这里删除它将导致不会丢失功能。 测试polyfill的路径,它将不包含在你的包中。</li>
<li>next.js 引入antd @zeit/next-css babel-plugin-import 按需加载无法正确编译css文件需要在next.config.js中配置服务端渲染方可。
<div class="cnblogs_code">
<pre>const withCss = require('@zeit/next-css'<span style="color: rgba(0, 0, 0, 1)">)
module.exports </span>=<span style="color: rgba(0, 0, 0, 1)"> withCss({
webpack: (config, { isServer }) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (isServer) {
const antStyles </span>= /antd\/.*?\/style\/css.*?/<span style="color: rgba(0, 0, 0, 1)">
const origExternals </span>=<span style="color: rgba(0, 0, 0, 1)"> [...config.externals]
config.externals </span>=<span style="color: rgba(0, 0, 0, 1)"> [
(context, request, callback) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (request.match(antStyles)) <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> callback()
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">typeof</span> origExternals === 'function'<span style="color: rgba(0, 0, 0, 1)">) {
origExternals[</span>0<span style="color: rgba(0, 0, 0, 1)">](context, request, callback)
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
callback()
}
},
...(</span><span style="color: rgba(0, 0, 255, 1)">typeof</span> origExternals === 'function' ?<span style="color: rgba(0, 0, 0, 1)"> [] : origExternals),
]
config.module.rules.unshift({
test: antStyles,
use: </span>'null-loader'<span style="color: rgba(0, 0, 0, 1)">,
})
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> config
},
})</span></pre>
</div>
</li>
<li>next.js 引入@zeit/less需要将antd的按需加载style改为true。</li>
<li>postCss/postCss-use 使用方法:
<div class="cnblogs_code">
<pre>module.exports =<span style="color: rgba(0, 0, 0, 1)"> {
plugins: [
require(</span>'postcss-use'<span style="color: rgba(0, 0, 0, 1)">)({
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> allow autoprefixer</span>
modules: [ 'autoprefixer'<span style="color: rgba(0, 0, 0, 1)"> ]
})
]
}</span></pre>
</div>
</li>
<li>analysis && antd 3.x.x version icon 异步加载(next配置方案) && moment 语言包打包优化。<br>
moment 语言包使用 webpack.IgnorePlugin 会把所有语言过滤掉,所以需要使用 webpack.ContextReplacementPlugin 来指定打包筛选方案,然后单独引入所需moment语言包即可!
<div class="cnblogs_code">
<pre>const webpack = require('webpack'<span style="color: rgba(0, 0, 0, 1)">)
const withSass </span>= require('@zeit/next-sass'<span style="color: rgba(0, 0, 0, 1)">);
const withBundleAnalyzer </span>= require("@zeit/next-bundle-analyzer"<span style="color: rgba(0, 0, 0, 1)">)
module.exports </span>=<span style="color: rgba(0, 0, 0, 1)"> withBundleAnalyzer(withSass({
analyzeServer: [</span>"server", "both"<span style="color: rgba(0, 0, 0, 1)">].includes(process.env.BUNDLE_ANALYZE),
analyzeBrowser: [</span>"browser", "both"<span style="color: rgba(0, 0, 0, 1)">].includes(process.env.BUNDLE_ANALYZE),
bundleAnalyzerConfig: {
server: {
analyzerMode: </span>'static'<span style="color: rgba(0, 0, 0, 1)">,
reportFilename: </span>'../../bundles/server.html'<span style="color: rgba(0, 0, 0, 1)">
},
browser: {
analyzerMode: </span>'static'<span style="color: rgba(0, 0, 0, 1)">,
reportFilename: </span>'../bundles/client.html'<span style="color: rgba(0, 0, 0, 1)">
}
},
webpack: (config, { dev }) </span>=><span style="color: rgba(0, 0, 0, 1)"> {
config.module.rules.push(
{
test: </span>/\.(ttf|eot|svg|png|jpg|gif|ico)(\?v=\.\.)?$/<span style="color: rgba(0, 0, 0, 1)">,
loader: </span>'file-loader'<span style="color: rgba(0, 0, 0, 1)">,
options: {
name: </span>'../../../.'<span style="color: rgba(0, 0, 0, 1)">
}
}, {
test: </span>/\.(css|scss)/<span style="color: rgba(0, 0, 0, 1)">,
loader: </span>'emit-file-loader'<span style="color: rgba(0, 0, 0, 1)">,
options: {
name: </span>'dist/.'<span style="color: rgba(0, 0, 0, 1)">
}
}, {
test: </span>/\.css$/<span style="color: rgba(0, 0, 0, 1)">,
use: [</span>'babel-loader', 'raw-loader', 'postcss-loader'<span style="color: rgba(0, 0, 0, 1)">]
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">, {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> test: /\.s(a|c)ss$/,</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> use: ['babel-loader', 'raw-loader', 'postcss-loader',</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> loader: 'sass-loader',</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> options: {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> includePaths: ['styles', 'node_modules']</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .map((d) => path.join(__dirname, d))</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .map((g) => glob.sync(g))</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> .reduce((a, c) => a.concat(c), [])</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ]</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 0, 0, 1)"> )
</span>!dev &&<span style="color: rgba(0, 0, 0, 1)"> config.module.rules.push({
loader:</span>'webpack-ant-icon-loader'<span style="color: rgba(0, 0, 0, 1)">,
enforce: </span>'pre'<span style="color: rgba(0, 0, 0, 1)">,
options:{
chunkName:</span>'antd-icons'<span style="color: rgba(0, 0, 0, 1)">
},
include: [
require.resolve(</span>'@ant-design/icons/lib/dist.js'<span style="color: rgba(0, 0, 0, 1)">)
]
})
</span>!dev &&<span style="color: rgba(0, 0, 0, 1)"> config.plugins.push(
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 阻止生成与正则表达式或过滤器函数匹配的模块import或require调用</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 引入未知包的时候webpack会推断出directory的包,然后全部打包进入bundle,此条配置允许覆盖推断信息,更加精确的配置打包数据</span>
<span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> webpack.ContextReplacementPlugin(
</span>/moment[\\\/]locale$/<span style="color: rgba(0, 0, 0, 1)">,
</span>/^\.\/(th)\.js$/<span style="color: rgba(0, 0, 0, 1)">
)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 加到next/webpack.js配置中</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> new webpack.optimize.CommonsChunkPlugin({</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> // name: 'icons',</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> // filename: 'icons.js',</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> minChunks: function (module, count) {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> if (dev || (module.resource && module.resource.includes('icons'))) {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> return false;</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }),</span>
<span style="color: rgba(0, 0, 0, 1)"> )
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> config
},
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> exportPathMap: function (defaultPathMap) {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> return {</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> '/': { page: '/' },</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> }</span>
}))</pre>
</div>
</li>
<li>针对低版本next使用的webpack3配置中使用webpack-icons-loader需要单独配置以及处理export之后的文件索引,方案为:
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> fs = require('fs'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">var</span> path = require('path'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> editWebpack (srcPath) {
let prefix </span>=<span style="color: rgba(0, 0, 0, 1)"> path.extname(srcPath)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 过滤除js和html的文件</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (prefix === '.js'<span style="color: rgba(0, 0, 0, 1)">) {
const data </span>= fs.readFileSync(srcPath, 'utf8'<span style="color: rgba(0, 0, 0, 1)">);
let line </span>= data.split('\n'<span style="color: rgba(0, 0, 0, 1)">)
let len </span>=<span style="color: rgba(0, 0, 0, 1)"> line.length
let newLines </span>= ''<span style="color: rgba(0, 0, 0, 1)">
let isEdit </span>= <span style="color: rgba(0, 0, 255, 1)">false</span>
<span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < len; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (i > 347 && i < 350<span style="color: rgba(0, 0, 0, 1)">) {
let isFind </span>= ~line.indexOf('(dev)'<span style="color: rgba(0, 0, 0, 1)">)
</span>!isEdit && (isEdit =<span style="color: rgba(0, 0, 0, 1)"> isFind)
line </span>= isFind ? ' if (dev || (module.resource && module.resource.includes(\'icons\') && count >= 0)) {'<span style="color: rgba(0, 0, 0, 1)"> : line
}
newLines </span>+= line + (i !== len - 1 ? '\n' : ''<span style="color: rgba(0, 0, 0, 1)">)
}
fs.writeFileSync(srcPath, newLines, </span>'utf8'<span style="color: rgba(0, 0, 0, 1)">);
isEdit </span>&& console.log('webpack update success:' + srcPath + '\n'<span style="color: rgba(0, 0, 0, 1)">)
}
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> editIcons (srcPath, tarPath) {
let prefix </span>=<span style="color: rgba(0, 0, 0, 1)"> path.extname(srcPath)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 过滤除js和html的文件</span>
<span style="color: rgba(0, 0, 255, 1)">if</span> (prefix === '.js'<span style="color: rgba(0, 0, 0, 1)">) {
const data </span>= fs.readFileSync(srcPath, 'utf8'<span style="color: rgba(0, 0, 0, 1)">);
fs.writeFileSync(tarPath, data, </span>'utf8'<span style="color: rgba(0, 0, 0, 1)">)
console.log(</span>'@ant-design update success:' + tarPath + '\n'<span style="color: rgba(0, 0, 0, 1)">)
}
}
editWebpack(</span>'./node_modules/next/dist/server/build/webpack.js'<span style="color: rgba(0, 0, 0, 1)">)
editIcons(</span>'./static/font/dist.js', './node_modules/@ant-design/icons/lib/dist.js')</pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> fs = require('fs'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">var</span> path = require('path'<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> findFolder (srcDir, tarDir) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 读取当前路径下的所有目录和文件,返回字符串数组</span>
fs.readdir(srcDir, <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err, files) {
files.forEach(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (file) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (!~file.indexOf('antd-icons')) <span style="color: rgba(0, 0, 255, 1)">return</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> srcPath =<span style="color: rgba(0, 0, 0, 1)"> path.join(srcDir, file)
</span><span style="color: rgba(0, 0, 255, 1)">var</span> tarPath =<span style="color: rgba(0, 0, 0, 1)"> path.join(tarDir, file)
fs.stat(srcPath, </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err, stats) {
</span>!stats.isDirectory() &&<span style="color: rgba(0, 0, 0, 1)"> copyFile(srcPath, tarPath)
})
})
})
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> copyFile(srcPath, tarPath) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建字节读取流</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> rs =<span style="color: rgba(0, 0, 0, 1)"> fs.createReadStream(srcPath)
rs.on(</span>'error', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
console.log(</span>'read error'<span style="color: rgba(0, 0, 0, 1)">, srcPath)
}
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建字节写入流</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> ws =<span style="color: rgba(0, 0, 0, 1)"> fs.createWriteStream(tarPath)
ws.on(</span>'error', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (err) {
console.log(</span>'write error'<span style="color: rgba(0, 0, 0, 1)">, tarPath)
}
})
ws.on(</span>'close', <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (ex) {
})
rs.pipe(ws)
console.log(</span>'ant-icons move success:' + srcPath + '\n'<span style="color: rgba(0, 0, 0, 1)">)
}
findFolder(</span>'./.next/', './out/_next/webpack/')</pre>
</div>
<p> </p>
</li>
</ol></div><br><br>
来源:https://www.cnblogs.com/universe-cosmo/p/10987778.html
頁:
[1]