简体   繁体   English

使用 Angular CLI 延迟加载应用程序主题样式

[英]Lazy load application theme styles with Angular CLI

I am trying to switch the href of a <link /> for theming purposes and the SCSS themes live in a packages folder of my monorepo that are symlinked in node_modules .我正在尝试切换<link />href以进行主题化,并且 SCSS 主题位于我的 monorepo 的包文件夹中,这些文件夹在 node_modules 中进行了node_modules I need to be able to compile and reference these.我需要能够编译和引用这些。

I came across the following fixed issue: angular/angular-cli#3401 and have been trying to implement something similar:我遇到了以下固定问题: angular/angular-cli#3401并且一直在尝试实现类似的东西:

"styles": [
    "styles.scss",
    {
        "input": "../node_modules/@org/themes/dark.scss",
        "output": "dark",
        "lazy": true
    }
],

My understanding (perhaps incorrect) was that this would compile the dark.scss file into dist/dark.bundle.css and that I would be able to load it via http://localhost:4200/dist/dark.bundle.css but it is not working as expected.我的理解(可能不正确)是这会将dark.scss文件编译为dist/dark.bundle.css并且我可以通过http://localhost:4200/dist/dark.bundle.css加载它但是它没有按预期工作。 Am I misunderstanding something or doing this completely wrong?我是误解了什么还是这样做完全错误?

How do I compile an SCSS file from node_modules that I can then lazy load in the app?如何从node_modules编译一个 SCSS 文件,然后我可以在应用程序中延迟加载? Is there another/better approach I could try instead?我可以尝试另一种/更好的方法吗?

Additional notes:附加说明:

  • Using Angular version 4.2.4使用 Angular 版本4.2.4
  • Using Angular CLI version 1.3.0使用 Angular CLI 1.3.0
  • The documentation for this approach 这种方法文档
  • I am working in a monorepo so node_modules/@org/themes is a symlink我在 monorepo 工作,所以node_modules/@org/themes是一个符号链接
  • I have tried using ng serve --preserve-symlinks option in case the above was the issue.我曾尝试使用ng serve --preserve-symlinks选项以防上述问题。 It made no difference它没有任何区别

I have looked into the way that the Angular Material docs website approaches this problem and it seems they have a custom build script that compiles the SCSS files to CSS files in the assets directory before serving the application.我已经研究了Angular Material 文档网站解决这个问题的方式,似乎他们有一个自定义构建脚本,可以在为应用程序提供服务之前将 SCSS 文件编译为assets目录中的 CSS 文件。 I thought the fixed issue above removed the need for this step but perhaps not.我认为上面的固定问题消除了这一步的需要,但也许不是。 Is this the only way it can be done?这是唯一可以做到的方法吗?

SOLVED已解决

Thanks to @Kuncevic.感谢@Kuncevic。 I was missing the --extract-css flag.我错过了--extract-css标志。

Working config:工作配置:

"styles": [
    "styles.scss",
    {
        "input": "../node_modules/@org/themes/src/dark.scss",
        "output": "themes/dark",
        "lazy": true
    }
],

And with the following serve script, I can access it via http://localhost:4200/themes/dark.bundle.css :使用以下服务脚本,我可以通过http://localhost:4200/themes/dark.bundle.css访问它:

ng serve --extract-css --preserve-symlinks

By setting "lazy": true means it won't appear in index.html but there is no mechanism that will lazy load that bundle for you, check that comment :通过设置"lazy": true意味着它不会出现在index.html但没有机制可以为您延迟加载该包,请检查该评论

The lazy option doesn't actually lazy load anything. lazy 选项实际上不会延迟加载任何东西。 It just prevents it from being executed on application startup.它只是阻止它在应用程序启动时执行。

I agree "lazy": true is a bit confusing at first.我同意"lazy": true起初有点令人困惑。

If you run ng build you can actually see what's gets outputed in your build and analyze all the files produced by cli.如果您运行ng build您实际上可以看到构建中输出的内容并分析 cli 生成的所有文件。

When you do:当你这样做时:

{
    "input": "../node_modules/@org/themes/dark.scss",
    "output": "dark",
    "lazy": true
}

You should be able to access your file directly at http://localhost:4200/dark.bundle.js but it wont appear in index.html as you set "lazy": true您应该能够直接在http://localhost:4200/dark.bundle.js上访问您的文件,但是当您设置"lazy": true它不会出现在index.html"lazy": true

If you want to get dark.bundle.css bundle instead of dark.bundle.js in dev mode you can use --extract-css flag.如果你想在开发模式下获得dark.bundle.css包而不是dark.bundle.js ,你可以使用--extract-css标志。

The reason why cli generating styles in to js bundle in dev mode is because this way is much quicker. cli 之所以在 dev 模式下将样式生成到js bundle 中,是因为这种方式要快得多。 Bud when you do prod build like ng buld --prod it will output in to .css by default anyway. Bud 当你像ng buld --prod那样做 prod 构建时,它会默认输出到.css

I know this is an old post, but I have not found a full example just fragments to implement lazy loading in Angular for CSS files or js files .我知道这是一篇旧帖子,但我还没有找到一个完整的例子,只是片段来在 Angular 中为CSS 文件js 文件实现延迟加载。 This is a solution with Angular 7.1.4 version and lazy loading of font-awesome 4.7 and bootstrap 4这是 Angular 7.1.4 版本和font-awesome 4.7bootstrap 4延迟加载的解决方案

  1. Install bootstrap and font-awesome安装 bootstrap 和 font-awesome
    npm install --save font-awesome bootstrap
  1. Edit your angular.json file to make sure that the compiler will generate separated files into the dist folder编辑angular.json文件以确保编译器将生成分离的文件到dist文件夹中

     "styles": [ "src/styles.css", { "input": "./node_modules/font-awesome/css/font-awesome.css", "lazy": true, "bundleName": "font-awesome" }, { "input": "./node_modules/bootstrap/dist/css/bootstrap.min.css", "lazy": true, "bundleName": "bootstrap" } ],

    Parameter explanations:参数说明:

"input" : "the location where the command from the 1st step will download bootstrap and font-awesome" "input" : "第一步中的命令将下载引导程序和字体的位置"

"lazy" : "the value of true will make sure that the compiler will not embed the bootstrap.min.css and font-awesome.css files into the compiled files which are send to browser" "lazy" : " true的值将确保编译器不会将bootstrap.min.cssfont-awesome.css文件嵌入到发送到浏览器的编译文件中"

"bundleName" : "is the name which you will find into dist folder" "bundleName" : "是您将在dist文件夹中找到的名称"

  1. According to this answer you have to add into index.html the following script inside the header tag under the <base href="/">根据答案,您必须在<base href="/">下的标头标记内添加以下脚本index.html
          <script>
             window.onload = function () {
              function loadScript(scriptUrl) {
                const script = document.createElement('script');
                script.src = scriptUrl;
                document.body.appendChild(script);
              }

              loadScript('font-awesome.js');
              loadScript('bootstrap.js');
            }

         </script>

NOTE: window.onload = function () used to make sure that the page is loaded (this because our files into the dist are in .js format; this is the quick way for Angular to compile)注意: window.onload = function ()用于确保页面被加载(这是因为我们进入dist的文件是.js格式;这是Angular编译的快捷方式)

  1. Run this command, to compile the application运行此命令,编译应用程序
    ng build --extract-css=false --prod

NOTE: on build we use --extract-css=false to generate .js files注意:在构建时我们使用--extract-css=false来生成.js文件

Testing测试

  • Go into the browser and change it to dev (F12 or right click and inspect element)进入浏览器并将其更改为 dev(F12 或右键单击并检查元素)
  • Select Network tab选择网络选项卡
  • Press Ctrl+Shift+R for hard reload按 Ctrl+Shift+R 进行硬重新加载

You must be able to see that the bootstrap.js and font-awesome.js are loaded separately like in the photo and also you be able to see for a moment the page without style => this is the moment when the style is loaded well after the DOM is loaded您必须能够看到 bootstrap.js 和 font-awesome.js 像照片中一样分别加载,并且您还可以看到没有样式的页面=> 这是样式加载良好的时刻DOM 加载后

在此处输入图片说明

Since I can't comment the accepted answer, I'll provide an important note to it as a separate one.由于我无法评论已接受的答案,因此我将为其单独提供一个重要说明。 Please move it there and delete from here if needed.如果需要,请将其移至此处并从此处删除。 So, the accepted answer is based on separate CSS file.因此,接受的答案基于单独的 CSS 文件。 Since Angular 6 you can't use neither --extract-css or -ec flags in package.json for ng serve , nor extractCss: true in angular.json for serve config section.从 Angular 6 开始,你不能package.jsonng serve extractCss: true --extract-css-ec标志,也不能在angular.jsonserve配置部分使用extractCss: true Though, you can use this approach to make it work.不过,您可以使用这种方法使其工作。 Then you can load your lazy style by using this approach with promise on APP_INITIALIZER .然后你可以通过在APP_INITIALIZER上使用这种方法来加载你的懒惰风格。

For anyone who want to use global css scipts in .angular-cli.json lazy loaded without hash I wrote following script (eg patch-ng-cli.js)对于任何想要在 .angular-cli.json 延迟加载而没有哈希的情况下使用全局 css scipts 的人,我编写了以下脚本(例如 patch-ng-cli.js)

const fs = require('fs');

const stylesFileToPatch = "node_modules/@angular/cli/models/webpack-configs/styles.js";

const regex = /extraPlugins\.push\(.*\}\)\)\;/;
const patchContent = `
        // PATCHED CONTENT START
        const globalStyles = utils_1.extraEntryParser(appConfig.styles, appRoot, 'styles');
        extraPlugins.push(new ExtractTextPlugin({ filename: getPath => {
            const generatedFileName = getPath(\`[name]\${hashFormat.extract}.bundle.css\`);
            const name = generatedFileName.split(".")[0];
            const globalAppStylesConfigEntry = globalStyles.find(path => path.output === name);
            if (globalAppStylesConfigEntry && globalAppStylesConfigEntry.lazy){
                console.log(\`\${name} will not be hashed due to lazy loading\`);
                return \`\${name}.bundle.css\`
            }
            console.log(generatedFileName);
            return generatedFileName;
        }}));
        // PATCHED CONTENT END
`;


fs.readFile(stylesFileToPatch, (err, data) => {
    if (err) { throw err; }

    const text = data.toString();

    const isAlreadyPatched = !!text.match("PATCHED CONTENT");

    if (isAlreadyPatched) return console.warn("-- already patched --", stylesFileToPatch);

    console.log('-- Patching ng-cli: ', stylesFileToPatch);
    const patchedContent = text.replace(regex, patchContent);

    const file = fs.openSync(stylesFileToPatch, 'r+');
    fs.writeFile(file, patchedContent, () => console.log("-- Patching -- OK"));
    fs.close(file);
});

Then run this script after npm install via npm scripts in package.json然后在 npm install 之后通过 package.json 中的 npm 脚本运行这个脚本

"postinstall": "node ./patch-ng-cli.js",

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM