Estou investigando a melhor maneira de adicionar um middleware ao meu servidor razzle para detectar sempre que ele serve um arquivo criado pela razzle que inclui um webpack [hash:8]
ou [contenthash:8]
no nome do arquivo. Discuti primeiro alguns dos problemas que estou encontrando aqui https://github.com/jaredpalmer/razzle/pull/1368#issuecomment -664015050
Gostaria que o razzle gerasse e exponha a lista de arquivos / ativos seguros para serem considerados "imutáveis" (para fins de definição de Cache-Control
cabeçalhos nas respostas) de uma forma que seja fácil de consumir sem transformação extra do arquivos chunks.json e / ou assets.json
NOTA: ao definir respostas de controle de cache de longa duração e imutáveis, quero evitar fazer qualquer tipo de "aproximação" sobre se um arquivo pode ser considerado imutável (também conhecido como regex para detectar um hash no nome do arquivo) porque um falso positivo pode levar a um arquivo sendo armazenado em cache imutavelmente por um longo tempo e não seria corrigível por uma invalidação de cache do lado do servidor, o que pode ser um problema muito doloroso de se solucionar.
TL; DR de por que é difícil tentar usar os arquivos json expostos no momento:
chunks.json
e assets.json
. chunks.json inclui arquivos de mapa de origem e assets.json tem arquivos como png / fonts etc que chunks.json não tem.(assets.json).client
(por exemplo: "client": { "js": "/static/js/bundle.6fc534aa.js" }
), assets.json agrupa todos os outros ativos em uma string vazia (por exemplo: "": { "js": "/static/js/0.cb47cee9.chunk.js" }
)."client": { "css": ["filename.css"] }
), se houver apenas um arquivo presente em assets.json, será apenas o string única (por exemplo: "client": { "css": "filename.css" }
)."json": "/../chunks.json"
que não é algo que eu acho que deveria estar lá (não tenho certeza se isso é um bug ou não), mas tenho que remover isso manualmente ao fazer a lista de arquivos que podem receber cabeçalhos de resposta de controle de cache de longa duração.chunks: ["1", "2", "3"]
ao chunks.json é um tanto chato porque significa que tenho que fazer um trabalho extra para filtrar (chunks.json).client.chunks
porque ele não contém um array de arquivos como (chunks.json).client.css
e (chunks.json).client.js
etc.client
nem apareciam no arquivo chunks.json
. Eu fiz / sugeri a alteração para alterá-lo para usar o (s) número (s) do bloco como chave, porque pelo menos eles aparecem no arquivo. A desvantagem disso é que agora chunks.json
e assets.json
diversificam ainda mais em seu esquema ao lidar com blocos que não são o bloco nomeado primário ( "client": {/* blah */ }
).Atualmente usando o assets.json e chunks.json, isso é o que tive que fazer até agora
Eu não tenho:
"chunks": ["1", "2", "3"]
e "json": "/../chunks.json"
function razzleCacheableFiles() {
// TODO: Add loading the assets.json file to support (png/txt files etc)
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const chunks = require(process.env.RAZZLE_CHUNKS_MANIFEST!);
const filesByType = Object.entries(chunks).reduce(
(chunkAcc: any, [, chunk]) => {
const types = Object.entries(chunk as any).reduce(
(typeAcc, [fileType, files]) => {
return {
[fileType]: chunkAcc[fileType]
? [...chunkAcc[fileType], ...(files as string[])]
: files,
};
},
{},
);
return types;
},
{},
);
const files = Object.entries(filesByType).reduce(
(acc: any[], [, files]) => [...acc, ...(files as string[])],
[],
);
return files;
}
const cacheableFiles = razzleCacheableFiles();
// Serve static files located under `process.env.RAZZLE_PUBLIC_DIR`
const assetCaching = {
immutable: {
maxAge: CacheFor.OneMonth,
sMaxAge: CacheFor.OneYear,
},
default: {
maxAge: CacheFor.OneDay,
sMaxAge: CacheFor.OneWeek,
}
};
app.use(
serve(process.env.RAZZLE_PUBLIC_DIR!, {
setHeaders(res, path) {
const filename = path.replace(process.env.RAZZLE_PUBLIC_DIR!, "");
const hasHashInFilename = cacheableFiles.includes(filename);
if (hasHashInFilename) {
const { immutable } = assetCaching;
res.setHeader(
"Cache-Control",
`max-age=${immutable.maxAge},s-maxage=${immutable.sMaxAge},immutable`,
);
return;
}
res.setHeader(
"Cache-Control",
`max-age=${assetCaching.default.maxAge},s-maxage=${asetCaching.default.sMaxAge}`,
);
},
}),
);
Uma descrição clara e concisa de qual é o comportamento / uso atual.
Provavelmente haveria muitas maneiras de fazer isso, mas a principal coisa que eu quero é apenas uma maneira de carregar uma matriz de todos os ativos armazenáveis / imutáveis gerados pelo razzle build. o resultado pode ser parecido com este:
// File: caching.json
// contains all files/assets with a hash in them regardless of what type of file they are.
{
"immutable": [
"/static/js/0.cb47cee9.chunk.js",
"/static/js/0.cb47cee9.chunk.js.map",
"/static/js/0.cb47cee9.chunk.js.LICENSE.txt",
"/static/media/ferris-error.407b714e.png"
],
// I'm not even sure if this is required because I don't think razzle generates any files that don't have hashes in them?
// possibly files copied in from the `public/` directory during build. but I'm not even sure if it'd that'd useful
"standard": []
}
// RAZZLE_CACHING_MANIFEST is probably a silly name but
const cacheableFiles = require(process.env.RAZZLE_CACHING_MANIFEST!);
// Serve static files located under `process.env.RAZZLE_PUBLIC_DIR`
const assetCaching = {
immutable: {
maxAge: CacheFor.OneMonth,
sMaxAge: CacheFor.OneYear,
},
default: {
maxAge: CacheFor.OneDay,
sMaxAge: CacheFor.OneWeek,
}
};
app.use(
serve(process.env.RAZZLE_PUBLIC_DIR!, {
setHeaders(res, path) {
const filename = path.replace(process.env.RAZZLE_PUBLIC_DIR!, "");
const hasHashInFilename = cacheableFiles.immutable.includes(filename);
if (hasHashInFilename) {
const { immutable } = assetCaching;
res.setHeader(
"Cache-Control",
`max-age=${immutable.maxAge},s-maxage=${immutable.sMaxAge},immutable`,
);
return;
}
res.setHeader(
"Cache-Control",
`max-age=${assetCaching.default.maxAge},s-maxage=${asetCaching.default.sMaxAge}`,
);
},
}),
);
Não investiguei totalmente qual seria uma boa solução, mas depois de tentar reunir esta lista de "ativos armazenáveis em cache" em tempo de execução usando assets.json
e chunks.json
, estou bastante convencido de que em um No mínimo, a melhor maneira de fazer isso seria em tempo de construção com algum tipo de plugin do webpack e contornar as inconsistências desses dois arquivos.
Para meus propósitos, provavelmente, inicialmente começarei a estudar como fazer isso com um plug-in em vez de em tempo de execução como venho fazendo, mas acho que haveria um valor significativo em ter isso integrado ao Razzle por padrão. Ser capaz de definir o controle de cache de longa duração em arquivos com hash é em grande parte o motivo pelo qual eles são hash, para começar, então, expor uma lista de todos esses arquivos parece apropriado.
Quaisquer usuários que desejam definir cabeçalhos de resposta de controle de cache imutáveis e de longa duração apropriados para arquivos gerados e hash pelo razzle.
chunks.json
e assets.json
(parece sujeito a erros e frágil).require(process.env.RAZZLE_CACHING_MANIFEST!)
. ()Eu estaria disposto a ajudar / contribuir para fazer essa mudança, mas posso precisar de um ponto de vista na direção certa (e, claro, se essa é ou não uma mudança que seria aceita / bem-vinda).
Além disso, ter algo como isso pode tornar mais fácil ter alguns testes / estabilidade para garantir que as coisas estão usando [contenthash:8]
vez de [hash:8]
(criar hash) se / quando eles podem https: / /github.com/jaredpalmer/razzle/issues/1331
Parece uma ideia que vale a pena.
Ele também está conectado a outro problema que é a configuração do chunkGroup na otimização. Porque se isso fosse configurado, a string vazia seria "shared", "framework" etc.
Se você olhar para next.js, eles usam uma configuração chunkGroups como esta.
Quando mudarmos isso, também será incompatível com as versões anteriores, mas isso tem que ser feito. Tenho mais algumas grandes mudanças em andamento que também precisam de um grande lançamento.
Mas sinta-se à vontade para criar um código que resolva isso 😀
Se você olhar para next.js, eles usam uma configuração chunkGroups como esta.
Legal, não entendi se / como outras ferramentas / frameworks abordam isso, você tem um link / exemplos?
Também está conectado a outro problema que é a configuração do chunkGroup na otimização
Um problema aberto do Razzle? você poderia me indicar qual deles para que eu possa ter mais contexto 😄
Eu acho que uma forma potencial de resolver isso é definir mais fortemente a forma / esquema dos chunks.json
e assets.json
. Provavelmente precisaria ser considerado com cuidado (e ter uma grande versão do solavanco), mas se houver exemplos de como outros frameworks etc resolveram o problema, pode fazer sentido seguir uma direção semelhante
E
https://github.com/vercel/next.js/blob/canary/packages/next/build/webpack-config.ts#L378
Não tenho certeza sobre como eles fazem o manifesto.
Dê uma olhada em https://github.com/jaredpalmer/razzle/issues/1377 agora, adicionado um novo exemplo :)
@fivethreeo Não consegui dedicar mais tempo especificamente a esse problema 😅, com certeza vou tentar passar algum tempo testando o pré-lançamento da v4. Se você acha que está pronto para isso, espero tentar testá-lo nos próximos dias.
Não tenho certeza se é de muito interesse, mas tornei o que estou trabalhando público agora aqui .
Estou muito interessado na v4 porque, com sorte, significa que posso remover o máximo de substituições de "plug-in" necessárias para definir as coisas aqui , especialmente para o texto digitado.
O material armazenável em cache está aqui .
Todos os arquivos usam contenthash agora. Os arquivos copiados, eu diria que são uma prática ruim quando temos um bundler.
Não tenho certeza se entendi o que você quis dizer com "Os arquivos copiados, eu diria que são uma má prática quando temos um bundler".
Atualmente, o comportamento é que se você colocar quaisquer arquivos na pasta de nível superior public/
em seu projeto razzle.
build/
public/
robots.txt
manifest.json
package.json
Eles são eliminados nos ativos estáticos quando você razzle build
build/
public/
robots.txt
manifest.json
static/
...
public/
robots.txt
manifest.json
package.json
Eu estava pensando que poderia ser desejável manter uma lista de todos os bens que foram copiados-in durante a compilação por isso eles são especificamente targettable separadamente para aplicar cache-controle para.
Acho que o argumento contra isso (que eu posso pensar) seria que pode não haver necessidade do usuário distinguir entre os arquivos que o razzle copiou durante a compilação e aqueles que podem ter sido colocados manualmente fora do razzle build
Acho que public deve conter apenas robots.txt e favicon.ico e eles não serão versionados por hashes.
Qualquer outra coisa deve ser empacotada pelo webpack. Quaisquer favicons maiores devem ser agrupados.
Talvez, mas mesmo se você quiser manter a compatibilidade "plug and play" com um create-react-app
padrão, pode valer a pena considerar que o manifesto do aplicativo e alguns ícones também estarão presentes lá .
Lembro-me vivamente de que há razões pelas quais manifest.json
/ manifest.webmanifest
não deve conter um hash de construção, que é uma das razões pelas quais é frequentemente excluído do processamento pelo empacotador. Posso estar errado / não lembrar, mas possivelmente algo a ver com PWAs e modo offline
Algum dos projetos de exemplo da razzle implementa suporte PWA (e / ou service worker)?
Talvez menos relevantes, mas algumas outras coisas que coloquei na pasta public/
no passado, ao usar criar-reagir-app, são arquivos para download relacionados ao site, mas onde URLs persistentes são necessários. Como ter um documento PDF que pode ser vinculado ao enviar e-mails, etc. 🤷
Tentando procurar exemplos de se / por que / quando os manifestos da web devem ser separados do empacotador:
Há um comentário nessa postagem que leva a https://github.com/w3c/manifest/issues/446#issuecomment -351368893
Sim, os arquivos para download devem ir para lá. Hm, mas como adicionamos esses arquivos ao assets.json? Alguma ideia? 😀Devemos fazer o webpack encontrá-los e agrupá-los como estão? Modificar o assets.json parece hackear.
Não acho que exista um exemplo de PWA. Mas se eles precisam de um nome consistente. Isso precisa ser tratado pelo webpack.
Vou substituir o plugin de ativos pelo plugin de manifesto para que possamos adaptar a saída.
Adicionado um novo manifesto de ativos com todos os arquivos https://github.com/jaredpalmer/razzle/commit/1c6e9169e9d8eee256d0f118f8a88da8de85989f alguma sugestão de melhorias?
Lançou um canário agora :)
Vejo que o plugin de manifesto não é realmente mantido. O melhor seria fazer o nosso. Mas atualmente não conheço ninguém além (talvez) de mim ou do pessoal do webpack que pode fazer isso.
Adicionado ao ramo de canário agora. Uma espécie de hack por enquanto. Mas funciona e é um começo que pode ser melhorado.
Depois de algumas considerações, não irei adicionar isso ao núcleo.
Mas aqui está o código que criei:
new ManifestPlugin({
fileName: path.join(paths.appBuild, 'assets.json'),
writeToFileEmit: true,
generate: (seed, files) => {
const entrypoints = new Set();
const noChunkFiles = new Set();
const longTermCacheFiles = new Set();
files.forEach(file => {
if (file.isChunk) {
const groups = (
(file.chunk || {})._groups || []
).forEach(group => entrypoints.add(group));
} else {
noChunkFiles.add(file);
}
if (!webpackOptions.fileLoaderExclude.some(re=>re.test(file.path))) {
let fileHasHash = /\[(build|content)?hash/.test(
typeof webpackOptions.fileLoaderOutputName == 'function' ?
webpackOptions.fileLoaderOutputName(file) : webpackOptions.fileLoaderOutputName);
if (fileHasHash) longTermCacheFiles.add(file);
} else if (webpackOptions.urlLoaderTest.some(re=>re.test(file.path))) {
let urlHasHash = /\[(build|content)?hash/.test(
typeof webpackOptions.urlLoaderOutputName == 'function' ?
webpackOptions.urlLoaderOutputName(file) : webpackOptions.urlLoaderOutputName);
if (urlHasHash) longTermCacheFiles.add(file);
} else if (webpackOptions.cssTest.some(re=>re.test(file.path))) {
let cssHasHash = /\[(build|content)?hash/.test(
typeof webpackOptions.cssOutputFilename == 'function' ?
webpackOptions.cssOutputFilename(file) : webpackOptions.cssOutputFilename);
if (cssHasHash) longTermCacheFiles.add(file);
} else if (webpackOptions.jsTest.some(re=>re.test(file.path))) {
let jsHasHash = /\[(build|content)?hash/.test(
typeof webpackOptions.jsOutputFilename == 'function' ?
webpackOptions.jsOutputFilename(file) : webpackOptions.jsOutputFilename);
if (jsHasHash) longTermCacheFiles.add(file);
}
});
const entries = [...entrypoints];
const entryArrayManifest = entries.reduce((acc, entry) => {
const name =
(entry.options || {}).name ||
(entry.runtimeChunk || {}).name ||
entry.id;
const allFiles = []
.concat(
...(entry.chunks || []).map(chunk =>
chunk.files.map(path => config.output.publicPath + path)
)
)
.filter(Boolean);
const filesByType = allFiles.reduce((types, file) => {
const fileType = file.slice(file.lastIndexOf('.') + 1);
types[fileType] = types[fileType] || [];
types[fileType].push(file);
return types;
}, {});
const chunkIds = [].concat(
...(entry.chunks || []).map(chunk => chunk.ids)
);
return name
? {
...acc,
[name]: { ...filesByType, chunks: chunkIds },
}
: acc;
}, seed);
entryArrayManifest['noentry'] = [...noChunkFiles]
.map(file => file.path)
.reduce((types, file) => {
const fileType = file.slice(file.lastIndexOf('.') + 1);
types[fileType] = types[fileType] || [];
types[fileType].push(file);
return types;
}, {});
entryArrayManifest['cacheable'] = [...longTermCacheFiles]
.map(file => file.path);
return entryArrayManifest;
},
})
Mas aprendi muito sobre ativos;)
Desculpe, não tenho conseguido gastar muito tempo com isso há algum tempo, mas parece legal. Estou dando uma olhada agora em como atualizar meu material para a última versão estável do Razzle e testando sua sugestão como um plugin personalizado.
Parece muito bom, mas estou um pouco confuso sobre isso:
let fileHasHash = /\[(build|content)?hash/.test(
typeof webpackOptions.fileLoaderOutputName == 'function'
? webpackOptions.fileLoaderOutputName(file)
: webpackOptions.fileLoaderOutputName);
if (fileHasHash) longTermCacheFiles.add(file);
O que webpackOptions.fileLoaderOutputName
pretende ser? para mim, sempre parece apenas indefinido.
Apenas em razzle canário
Legal, fiz alguns progressos agora com a obtenção de um galho em meu projeto para trabalhar no galho de canário. Não está funcionando bem, no momento meus problemas parecem estar principalmente relacionados com a configuração do carregador do babel para reconhecer pacotes irmãos. Consigo construir, mas consigo problemas de "não consigo encontrar o módulo" quando tento executá-lo.
Isso provavelmente não é muito interessante / útil, mas:
https://github.com/bootleg-rust/sites/pull/2/files
da memória, originalmente peguei emprestada a configuração de https://github.com/jaredpalmer/razzle/issues/664
/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime sync:2
var e = new Error("Cannot find module '" + req + "'");
^
Error: Cannot find module 'undefined'
at require (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime sync:2:10)
at razzleCacheableFiles (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime/server.tsx:106:18)
at createKoaApp (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/lib-ssr-runtime/server.tsx:61:26)
at Module.call (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/src/server.tsx:42:13)
at a (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:19:22)
at Object.call (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/server.js:1:31123)
at __webpack_require__ (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:19:22)
at /Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/webpack:/webpack/bootstrap:83:10
at Object.<anonymous> (/Users/jstableford/Desktop/@bootleg-rust/sites/packages/web-rust-lang/build/server.js:1:935)
https://github.com/jaredpalmer/razzle/issues/1459
e defina NODE_PATH = .. / ou algo assim
Talvez devêssemos mudar algumas coisas aqui:
https://github.com/jaredpalmer/razzle/blob/canary/packages/razzle/config/modules.js
Ok, investigando um pouco mais, acabei de perceber que o problema está apenas fazendo com que process.env.RAZZLE_CHUNKS_MANIFEST
não seja mais definido 😅.
A única coisa que eu estava usando era para detectar quais ativos podiam ser armazenados em cache, então parece que devo ser capaz de fornecer a nova configuração ManifestPlugin
você vinculou uma chance agora para substituí-la 🎉.
OK!
Fiz um plugin personalizado em meu projeto que parece funcionar bem o suficiente para o meu caso de uso por enquanto. O código que você criou foi muito útil, tendo isso como ponto de partida.
Eu mudei um pouco, mas para sua informação, acho que há um problema onde ele pensa que tudo é processado por file-loader
porque ele usa Array.prototype.every()
vez de Array.prototype.some()
: !webpackOptions.fileLoaderExclude.every(re=>re.test(file.path))
Caso seja útil compartilhar aqui:
function modifyWebpackConfig({
env: { target, dev },
webpackConfig,
webpackObject,
options: { pluginOptions, razzleOptions, webpackOptions },
paths,
}) {
// TODO: allow passing in extra file categorizers with `pluginOptions`
const fileCategorizers = [
{
test: webpackOptions.urlLoaderTest,
outputName: webpackOptions.urlLoaderOutputName,
},
{
test: webpackOptions.cssTest,
outputName: webpackOptions.cssOutputFilename,
},
{
test: webpackOptions.jsTest,
outputName: webpackOptions.jsOutputFilename,
},
{
exclude: webpackOptions.fileLoaderExclude,
outputName: webpackOptions.fileLoaderOutputName,
},
];
const fileName = path.join(paths.appBuild, "cacheable-assets.json");
const assetPlugin = new WebpackManifestPlugin({
fileName,
writeToFileEmit: true,
generate: (seed, files) => {
const notHashedFiles = new Set();
const hashedFiles = new Set();
const setFileAs = (file, { containsHash }) => {
if (containsHash) {
hashedFiles.add(file);
} else {
notHashedFiles.add(file);
}
};
files.forEach((file) => {
if (file.name.startsWith("..")) {
// Files that start with ".." will live outside of the public/
// folder and therefore can't/shouldn't be accessed.
return;
}
const fileCategorized = fileCategorizers.some(
({ test, exclude, outputName }) => {
const passesTest =
test != null ? fileMatchesAnyRegexp(file, test) : true;
const passesExclude =
exclude != null ? !fileMatchesAnyRegexp(file, exclude) : true;
const fileMatches =
passesTest &&
passesExclude &&
fileMatchesTemplate(file.path, outputName);
if (fileMatches) {
const containsHash = webpackLoaderOutputContainsHash(
outputName,
file,
);
setFileAs(file, { containsHash });
}
return fileMatches;
},
);
if (!fileCategorized) {
// TODO: allow "strict" vs "lazy" mode here where we can only use
// regex on the filename to guess if a file contains a hash in it.
setFileAs(file, { containsHash: false });
}
});
const mutable = [...notHashedFiles].map((file) => file.path);
const immutable = [...hashedFiles].map((file) => file.path);
return {
mutable,
immutable,
};
},
});
if (target === "web") {
webpackConfig.plugins.push(assetPlugin);
}
if (target === "node") {
// NOTE: adding multiple DefinePlugin's causes issues
// so we have to find and edit the existing one.
const definePlugin = webpackConfig.plugins.find(
(p) => p.constructor.name === "DefinePlugin",
);
definePlugin.definitions[
"process.env.RAZZLE_PLUGIN_CACHEABLE_ASSETS"
] = JSON.stringify(fileName);
}
return webpackConfig;
}
const cacheableAssetsPlugin = {
modifyWebpackConfig,
};
Ou pode dar uma olhada aqui https://github.com/bootleg-rust/sites/pull/2/files#diff -59ee436c0396a1f925f067b7e7cbcdee354003236a279e0a87cf8831c7f587e3
Ah certo, sim, obrigado. Ainda estou me acostumando com os novos ganchos do plugin, gostei 🎉!
Acho que o único problema principal que ainda estou tendo e que não consegui resolver é que por algum motivo o scss
plugin / carregador não funciona quando executado no modo de desenvolvimento usando razzle start
mas se eu fizer um razzle build
completo, tudo parecerá bem.
Alguma ideia do que isso possa ser? ou vale a pena colocar isso em um problema diferente do github em algum lugar?
Use também modifyPaths para caminhos personalizados para que possam ser compostos.
Não funciona como?
Pode ser um novo problema .. :)
Esqueça, o sass loader não funcionando não era nada específico com o Razzle. algo a ver com uma incompatibilidade de versão ou algo com a versão de react-scripts
e / ou livro de histórias que eu tinha em um pacote irmão que estava carregando dependências.
Adicionados ganchos para manuseio de ativos, fechamento 😀
Vejo que você adicionou um plugin externo. Eu ainda preciso consertar isso para cliente / servidor / sem servidor. Tem alguma ideia para isso no canário? Um pouco preso.
Os ganchos que você usa agora.
Vejo que você adicionou um plugin externo. Eu ainda preciso consertar isso para cliente / servidor / sem servidor. Tem alguma ideia para isso no canário? Um pouco preso.
Definitivamente, achei muito conveniente (principalmente no servidor) agrupar por padrão todos os node_modules
em build/server.js
. Ser capaz de excluir a pasta node_modules
inteiramente de minhas imagens do docker de produção parece muito bom.
Dito isso, não tive a necessidade de usar / testar como funciona com quaisquer dependências nativas / específicas da plataforma (tenho a sensação de que coisas como imagemagick teriam problemas)
Meu processo de pensamento geral com o plugin "externo" que fiz é:
const externalsPluginOptions = {
// By default the NodeJS process uses the externals function razzle has and relies on `node_modules` to still be available
// after performing a razzle build. Setting this to `true` would mean that all dependencies attempt to get bundled into
// the build/ output unless explicitly specified as an external
resetNodeExternals: false,
// This probably wouldn't actually be required because the browser runtime
// doesn't have externals by default (i'm assuming)
resetWebExternals: true,
webExternals: [
// add externals for the web runtime here
],
nodeExternals: [
// add externals for the node runtime here
],
};
Para ser honesto, antes de decidir por uma API de configuração "adequada" para isso (particularmente se fosse no razzle core), provavelmente teria que ler a documentação do webpack para externals
com um pouco mais de profundidade no diferentes casos de uso para externos 😅.
No momento, estou apenas usando-o para redefinir os externos para que fiquem vazios para que eu tenha tudo empacotado em um aplicativo facilmente portátil que não depende de node_modules em tempo de execução
Comentários muito úteis
Lançou um canário agora :)